Skip to content
Snippets Groups Projects
Commit 2479587d authored by Manuel Krombholz's avatar Manuel Krombholz Committed by René Schöne
Browse files

Resolve "Add processing frequency option for items"

parent 93fbab4a
Branches
No related tags found
2 merge requests!19dev to master,!11Resolve "Add processing frequency option for items"
...@@ -21,6 +21,8 @@ aspect ItemHandling { ...@@ -21,6 +21,8 @@ aspect ItemHandling {
eq ItemWithDoubleState.getStateAsString() = Double.toString(getState()); eq ItemWithDoubleState.getStateAsString() = Double.toString(getState());
eq ItemWithStringState.getStateAsString() = getState(); eq ItemWithStringState.getStateAsString() = getState();
syn LastChanged Item.getLastChanged() = new LastChanged();
//--- getStateAsDouble --- //--- getStateAsDouble ---
syn double Item.getStateAsDouble(); syn double Item.getStateAsDouble();
// TupleHSB and String work like default // TupleHSB and String work like default
...@@ -285,7 +287,7 @@ aspect ItemHandling { ...@@ -285,7 +287,7 @@ aspect ItemHandling {
//--- stateUpdated --- //--- stateUpdated ---
/** /**
* Called, whenever the state of an item is updated. Does various things including: * Called, whenever the state of an item is updated. Does various things (except it has no parent) including:
* <ul> * <ul>
* <li>Send the new state via MQTT</li> * <li>Send the new state via MQTT</li>
* <li>Send the new state to Influx DB</li> * <li>Send the new state to Influx DB</li>
...@@ -294,6 +296,7 @@ aspect ItemHandling { ...@@ -294,6 +296,7 @@ aspect ItemHandling {
* @param shouldSendState whether to send the new state (currently affects MQTT and Influx) * @param shouldSendState whether to send the new state (currently affects MQTT and Influx)
*/ */
protected void Item.stateUpdated(boolean shouldSendState) { protected void Item.stateUpdated(boolean shouldSendState) {
if (getParent() == null) { return; }
if (shouldSendState) { if (shouldSendState) {
try { try {
// sendState() refined in MQTT and Influx aspect // sendState() refined in MQTT and Influx aspect
...@@ -302,8 +305,12 @@ aspect ItemHandling { ...@@ -302,8 +305,12 @@ aspect ItemHandling {
logger.catching(e); logger.catching(e);
} }
} }
if (this.getLastChanged().checkStateProcessingTime(relevantFrequencySetting())) {
this.getLastChanged().afterStateChangeProcessed();
getItemObserver().apply(); getItemObserver().apply();
} }
}
//--- sendState --- //--- sendState ---
protected void Item.sendState() throws Exception { protected void Item.sendState() throws Exception {
...@@ -459,6 +466,11 @@ aspect ItemHandling { ...@@ -459,6 +466,11 @@ aspect ItemHandling {
} }
//--- onReceiveStateChange ---
protected void Item.onReceiveStateChange() {
//Instant lastChange = this.
}
...@@ -506,4 +518,6 @@ aspect ItemHandling { ...@@ -506,4 +518,6 @@ aspect ItemHandling {
syn String ItemUpdate.getNewStateAsString(); syn String ItemUpdate.getNewStateAsString();
eq ItemUpdateColor.getNewStateAsString() = getNewHSB().toString(); eq ItemUpdateColor.getNewStateAsString() = getNewHSB().toString();
eq ItemUpdateDouble.getNewStateAsString() = Double.toString(getNewValue()); eq ItemUpdateDouble.getNewStateAsString() = Double.toString(getNewValue());
} }
aspect LastChanged {
public void LastChanged.afterStateChangeProcessed() {
this.setValue(Instant.now());
}
public boolean LastChanged.checkStateProcessingTime(FrequencySetting FrequencySetting) {
if (FrequencySetting==null) {
return true;
}
double frequency = FrequencySetting.getEventProcessingFrequency();
Instant lastStateChange = this.getValue();
if (lastStateChange==null) {
return true;
}
return lastStateChange.toEpochMilli() + (1/frequency)*1000 < Instant.now().toEpochMilli();
}
}
\ No newline at end of file
...@@ -11,6 +11,48 @@ aspect Navigation { ...@@ -11,6 +11,48 @@ aspect Navigation {
return result; return result;
} }
//--- enclosingGroup ---
inh Group Group.enclosingGroup();
inh Group Item.enclosingGroup();
eq Group.getItem().enclosingGroup() = this;
eq Group.getGroup().enclosingGroup() = this;
eq SmartHomeEntityModel.getGroup().enclosingGroup() = null;
eq SmartHomeEntityModel.getActivityItem().enclosingGroup() = null;
//--- relevantFrequencySetting ---
syn FrequencySetting Group.relevantFrequencySetting() {
// first, use value defined on group itself, if any
if (this.hasFrequencySetting()) {
return this.getFrequencySetting();
}
// recursively use enclosing group and use value from there, if any
Group parent = enclosingGroup();
if (parent != null) {
return parent.relevantFrequencySetting();
}
// if top-level group without FrequencySetting
return null;
}
syn FrequencySetting Item.relevantFrequencySetting() {
// first, use value defined on item itself, if any
if (this.hasFrequencySetting()) {
return this.getFrequencySetting();
}
// use enclosing group and use value from there, if any
Group parent = enclosingGroup();
if (parent != null) {
return parent.relevantFrequencySetting();
}
// if top-level item without FrequencySetting
return null;
}
//--- addItems ---
private void SmartHomeEntityModel.addItems(java.util.List<Item> result, JastAddList<Group> groups) { private void SmartHomeEntityModel.addItems(java.util.List<Item> result, JastAddList<Group> groups) {
groups.forEach(group -> group.getItemList().forEach(item -> result.add(item))); groups.forEach(group -> group.getItemList().forEach(item -> result.add(item)));
} }
...@@ -56,4 +98,5 @@ aspect Navigation { ...@@ -56,4 +98,5 @@ aspect Navigation {
eq Root.getRule().getRoot() = this; eq Root.getRule().getRoot() = this;
eq Root.getUser().getRoot() = this; eq Root.getUser().getRoot() = this;
eq Root.getLocation().getRoot() = this; eq Root.getLocation().getRoot() = this;
eq Root.getFrequencySetting().getRoot() = this;
} }
...@@ -98,9 +98,22 @@ aspect Resolving { ...@@ -98,9 +98,22 @@ aspect Resolving {
return java.util.Optional.empty(); return java.util.Optional.empty();
} }
syn java.util.Optional<FrequencySetting> Root.resolveFrequencySetting(String performanceId) {
for (FrequencySetting performance : getFrequencySettingList()) {
if (performance.getLabel().equals(performanceId)) {
return java.util.Optional.of(performance);
}
}
return java.util.Optional.empty();
}
// implementing resolving for relations // implementing resolving for relations
refine RefResolverStubs eq StateSyncGroup.resolveTargetItemByToken(String id, int position) { refine RefResolverStubs eq StateSyncGroup.resolveTargetItemByToken(String id, int position) {
return getRoot().getSmartHomeEntityModel().resolveItem(id).orElseThrow(() -> new RuntimeException("Item '" + id + "' not found!")); return getRoot().getSmartHomeEntityModel().resolveItem(id).orElseThrow(() -> new RuntimeException("Item '" + id + "' not found!"));
} }
refine RefResolverStubs eq ASTNode.globallyResolveFrequencySettingByToken(String id) {
return getRoot().resolveFrequencySetting(id).orElseThrow(() -> new RuntimeException("FrequencySetting '" + id + "' not found!"));
}
} }
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
Rule ::= Condition* Action* ; Rule ::= Condition* Action* ;
abstract Condition ; abstract Condition ;
ItemStateCheckCondition : Condition ::= ItemStateCheck ; ItemStateCheckCondition : Condition ::= ItemStateCheck ;
ItemStateChangeCondition : Condition ::= Item; ItemStateChangeCondition : Condition ;
rel ItemStateChangeCondition.Item -> Item;
ExpressionCondition : Condition ::= LogicalExpression ; ExpressionCondition : Condition ::= LogicalExpression ;
abstract Action ; abstract Action ;
NoopAction : Action ; NoopAction : Action ;
...@@ -29,5 +30,6 @@ MultiplyDoubleToStateAction : SetStateAction ::= <Multiplier:double> ; ...@@ -29,5 +30,6 @@ MultiplyDoubleToStateAction : SetStateAction ::= <Multiplier:double> ;
ItemObserver ::= ; ItemObserver ::= ;
rel ItemObserver.TriggeredRule* <-> Rule.Observer* ; rel ItemObserver.TriggeredRule* <-> Rule.Observer* ;
FrequencySetting : LabelledModelElement ::= <EventProcessingFrequency:double> ;
StateSyncGroup : Rule ; StateSyncGroup : Rule ;
rel StateSyncGroup.TargetItem* -> Item; rel StateSyncGroup.TargetItem* -> Item;
...@@ -87,6 +87,9 @@ Comment = "//" [^\n\r]+ ...@@ -87,6 +87,9 @@ Comment = "//" [^\n\r]+
"incoming" { return sym(Terminals.INCOMING); } "incoming" { return sym(Terminals.INCOMING); }
"items" { return sym(Terminals.ITEMS); } "items" { return sym(Terminals.ITEMS); }
"itemType" { return sym(Terminals.ITEM_TYPE); } "itemType" { return sym(Terminals.ITEM_TYPE); }
"FrequencySetting" { return sym(Terminals.FREQUENCY_SETTING); }
"performance" { return sym(Terminals.PERFORMANCE); }
"procFreq" { return sym(Terminals.PROCESS_FREQUENCY); }
"label" { return sym(Terminals.LABEL); } "label" { return sym(Terminals.LABEL); }
"links" { return sym(Terminals.LINKS); } "links" { return sym(Terminals.LINKS); }
"metaData" { return sym(Terminals.META_DATA); } "metaData" { return sym(Terminals.META_DATA); }
......
...@@ -41,6 +41,7 @@ Root goal = ...@@ -41,6 +41,7 @@ Root goal =
| influx_root.ir goal.r {: r.setInfluxRoot(ir); return r; :} | influx_root.ir goal.r {: r.setInfluxRoot(ir); return r; :}
| machine_learning_root.ml goal.r {: r.setMachineLearningRoot(ml); return r; :} | machine_learning_root.ml goal.r {: r.setMachineLearningRoot(ml); return r; :}
| rule.rule goal.r {: r.addRule(rule); return r; :} | rule.rule goal.r {: r.addRule(rule); return r; :}
| frequency_setting.ip goal.r {: r.addFrequencySetting(ip); return r; :}
| thing.t {: return eph.createRoot(t); :} | thing.t {: return eph.createRoot(t); :}
| item.i {: return eph.createRoot(); :} | item.i {: return eph.createRoot(); :}
| group.g {: return eph.createRoot(g); :} | group.g {: return eph.createRoot(g); :}
...@@ -53,6 +54,7 @@ Root goal = ...@@ -53,6 +54,7 @@ Root goal =
| influx_root.ir {: return eph.createRoot(ir); :} | influx_root.ir {: return eph.createRoot(ir); :}
| machine_learning_root.ml {: return eph.createRoot(ml); :} | machine_learning_root.ml {: return eph.createRoot(ml); :}
| rule.rule {: return eph.createRoot(rule); :} | rule.rule {: return eph.createRoot(rule); :}
| frequency_setting.ip {: return eph.createRoot(ip); :}
; ;
%left RB_ROUND; %left RB_ROUND;
...@@ -128,28 +130,28 @@ Item item = ...@@ -128,28 +130,28 @@ Item item =
| ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new DefaultItem(), ib); :} | ITEM COLON item_body.ib SEMICOLON {: return eph.retype(new DefaultItem(), ib); :}
; ;
// ITEM_TYPE Item: id="" label="" state="" category="" topic="" metaData={"key":"value"} ; // ITEM_TYPE Item: id="" label="" state="" category="" topic="" performance="" metaData={"key":"value"} ;
Item item_body = Item item_body =
ID EQUALS TEXT.n item_body.i {: return eph.setID(i, n); :} ID EQUALS TEXT.n item_body.i {: return eph.setID(i, n); :}
| LABEL EQUALS TEXT.n item_body.i {: i.setLabel(n); return i; :} | LABEL EQUALS TEXT.n item_body.i {: i.setLabel(n); return i; :}
| STATE EQUALS TEXT.n item_body.i {: i.setStateFromString(n); return i; :} | STATE EQUALS TEXT.n item_body.i {: i.setStateFromString(n); return i; :}
| TOPIC EQUALS TEXT.n item_body.i {: return eph.setTopic(i, n); :} | TOPIC EQUALS TEXT.n item_body.i {: return eph.setTopic(i, n); :}
| CATEGORY EQUALS TEXT.n item_body.i {: return eph.setCategory(i, n); :} | CATEGORY EQUALS TEXT.n item_body.i {: return eph.setCategory(i, n); :}
| PERFORMANCE EQUALS frequency_setting_ref.ip item_body.i {: i.setFrequencySetting(ip); return i; :}
| META_DATA EQUALS string_map.md item_body.i | META_DATA EQUALS string_map.md item_body.i
{: return eph.setMetaData(i, md); :} {: return eph.setMetaData(i, md); :}
| {: return eph.createItem(); :} | {: return eph.createItem(); :}
; ;
Item item_ref = Item item_ref = TEXT.n {: return Item.createRef(n); :};
TEXT.n {: return Item.createRef(n); :} FrequencySetting frequency_setting_ref = TEXT.n {: return FrequencySetting.createRef(n); :};
;
Group group = Group group =
GROUP COLON group_body.gb SEMICOLON {: return gb; :} GROUP COLON group_body.gb SEMICOLON {: return gb; :}
; ;
// Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] aggregation=""; // Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] performance="" aggregation="";
// Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] aggregation="" ("",""); // Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] performance="" aggregation="" ("","");
Group group_body = Group group_body =
ID EQUALS TEXT.n group_body.g {: return eph.setID(g, n); :} ID EQUALS TEXT.n group_body.g {: return eph.setID(g, n); :}
| LABEL EQUALS TEXT.n group_body.g {: g.setLabel(n); return g; :} | LABEL EQUALS TEXT.n group_body.g {: g.setLabel(n); return g; :}
...@@ -158,6 +160,7 @@ Group group_body = ...@@ -158,6 +160,7 @@ Group group_body =
| AGGREGATION EQUALS TEXT.n group_body.g {: return eph.setSimpleAggregationFunction(g, n); :} | AGGREGATION EQUALS TEXT.n group_body.g {: return eph.setSimpleAggregationFunction(g, n); :}
| AGGREGATION EQUALS TEXT.n round_string_list.params group_body.g | AGGREGATION EQUALS TEXT.n round_string_list.params group_body.g
{: return eph.setParameterizedAggregationFunction(g, n, params); :} {: return eph.setParameterizedAggregationFunction(g, n, params); :}
| PERFORMANCE EQUALS frequency_setting_ref.ip group_body.g {: g.setFrequencySetting(ip); return g; :}
| {: return new Group(); :} | {: return new Group(); :}
; ;
...@@ -365,3 +368,14 @@ IntegerKeyMap integer_map_body = ...@@ -365,3 +368,14 @@ IntegerKeyMap integer_map_body =
return result; return result;
:} :}
; ;
FrequencySetting frequency_setting =
FREQUENCY_SETTING COLON frequency_setting_body.ipb SEMICOLON {: return ipb; :}
;
// FrequencySetting: id="" procFreq="" persFreq="";
FrequencySetting frequency_setting_body =
ID EQUALS TEXT.n frequency_setting_body.ip {: return eph.setID(ip, n); :}
| PROCESS_FREQUENCY EQUALS TEXT.n frequency_setting_body.ip {: ip.setEventProcessingFrequency(Double.parseDouble(n)); return ip; :}
| {: return new FrequencySetting(); :}
;
// ---------------- Main ------------------------------ // ---------------- Main ------------------------------
Root ::= SmartHomeEntityModel User* MqttRoot InfluxRoot MachineLearningRoot Rule* Location* ; Root ::= SmartHomeEntityModel User* MqttRoot InfluxRoot MachineLearningRoot Rule* Location* FrequencySetting*;
// ---------------- Users ------------------------------ // ---------------- Users ------------------------------
User : LabelledModelElement ; User : LabelledModelElement ;
......
// ---------------- openHAB ------------------------------ // ---------------- openHAB ------------------------------
SmartHomeEntityModel ::= Thing* Group* ThingType* ChannelType* ChannelCategory* ItemCategory* /ActivityItem:Item/ ; SmartHomeEntityModel ::= Thing* Group* ThingType* ChannelType* ChannelCategory* ItemCategory* /ActivityItem:Item/ ;
abstract ModelElement ::= <ID:String> ; abstract ModelElement ::= <ID:String> ;
abstract LabelledModelElement : ModelElement ::= <Label:String> ; abstract LabelledModelElement : ModelElement ::= <Label:String> ;
abstract DescribableModelElement : LabelledModelElement ::= <Description:String> ; abstract DescribableModelElement : LabelledModelElement ::= <Description:String> ;
...@@ -25,10 +26,9 @@ rel Channel.LinkedItem* <-> Item.Channel? ; ...@@ -25,10 +26,9 @@ rel Channel.LinkedItem* <-> Item.Channel? ;
Parameter : DescribableModelElement ::= <Type:ParameterValueType> [DefaultValue:ParameterDefaultValue] <Context:String> <Required:boolean> ; Parameter : DescribableModelElement ::= <Type:ParameterValueType> [DefaultValue:ParameterDefaultValue] <Context:String> <Required:boolean> ;
ParameterDefaultValue ::= <Value:String> ; ParameterDefaultValue ::= <Value:String> ;
abstract Item : LabelledModelElement ::= <_fetched_data:boolean> MetaData:ItemMetaData* /ItemObserver/; abstract Item : LabelledModelElement ::= <_fetched_data:boolean> MetaData:ItemMetaData* /ItemObserver/ /LastChanged/;
rel Item.Category? -> ItemCategory ; rel Item.Category? -> ItemCategory ;
rel Item.FrequencySetting? -> FrequencySetting ;
abstract ItemWithBooleanState : Item ::= <_state:boolean> ; abstract ItemWithBooleanState : Item ::= <_state:boolean> ;
abstract ItemWithStringState : Item ::= <_state:String> ; abstract ItemWithStringState : Item ::= <_state:String> ;
...@@ -51,8 +51,14 @@ ItemMetaData ::= <Key:String> <Value:String> ; ...@@ -51,8 +51,14 @@ ItemMetaData ::= <Key:String> <Value:String> ;
ItemCategory ::= <Name:String> ; ItemCategory ::= <Name:String> ;
LastChanged ::= <Value:Instant> ;
Group : LabelledModelElement ::= Group* Item* [AggregationFunction:GroupAggregationFunction] ; Group : LabelledModelElement ::= Group* Item* [AggregationFunction:GroupAggregationFunction] ;
rel Group.FrequencySetting? -> FrequencySetting ;
abstract GroupAggregationFunction ; abstract GroupAggregationFunction ;
SimpleGroupAggregationFunction : GroupAggregationFunction ::= <FunctionName:SimpleGroupAggregationFunctionName> ; SimpleGroupAggregationFunction : GroupAggregationFunction ::= <FunctionName:SimpleGroupAggregationFunctionName> ;
ParameterizedGroupAggregationFunction : GroupAggregationFunction ::= <FunctionName:ParameterizedGroupAggregationFunctionName> ParameterizedGroupAggregationFunction : GroupAggregationFunction ::= <FunctionName:ParameterizedGroupAggregationFunctionName>
<Param1:String> <Param2:String> ; <Param1:String> <Param2:String> ;
...@@ -24,16 +24,18 @@ public class EraserParserHelper { ...@@ -24,16 +24,18 @@ public class EraserParserHelper {
private Map<String, Parameter> parameterMap = new HashMap<>(); private Map<String, Parameter> parameterMap = new HashMap<>();
private Map<String, Item> itemMap = new HashMap<>(); private Map<String, Item> itemMap = new HashMap<>();
private Map<String, Group> groupMap = new HashMap<>(); private Map<String, Group> groupMap = new HashMap<>();
private Map<String, FrequencySetting> FrequencySettingMap = new HashMap<>();
private Map<Thing, String> missingThingTypeMap = new HashMap<>(); private Map<Thing, String> missingThingTypeMap = new HashMap<>();
private Map<Channel, String> missingChannelTypeMap = new HashMap<>(); private Map<Channel, String> missingChannelTypeMap = new HashMap<>();
private Map<Item, String> missingTopicMap = new HashMap<>(); private Map<Item, String> missingTopicMap = new HashMap<>();
private Map<Item, String> missingItemCategoryMap = new HashMap<>(); private Map<Item, String> missingItemCategoryMap = new HashMap<>();
private Map<Designator, String> missingItemForDesignator = new HashMap<>(); private Map<Designator, String> missingItemForDesignator = new HashMap<>();
private Map<Thing, Iterable<String>> missingChannelListMap = new HashMap<>(); private Map<Thing, Iterable<String>> missingChannelListMap = new HashMap<>();
private Map<Channel, Iterable<String>> missingItemLinkListMap = new HashMap<>(); private Map<Channel, Iterable<String>> missingItemLinkListMap = new HashMap<>();
private Map<Item, Iterable<String>> missingControllingListMap = new HashMap<>();
private Map<Group, Iterable<String>> missingSubGroupListMap = new HashMap<>(); private Map<Group, Iterable<String>> missingSubGroupListMap = new HashMap<>();
private Map<Group, Iterable<String>> missingItemListMap = new HashMap<>(); private Map<Group, Iterable<String>> missingItemListMap = new HashMap<>();
private Map<ThingType, Iterable<String>> missingChannelTypeListMap = new HashMap<>(); private Map<ThingType, Iterable<String>> missingChannelTypeListMap = new HashMap<>();
...@@ -94,19 +96,20 @@ public class EraserParserHelper { ...@@ -94,19 +96,20 @@ public class EraserParserHelper {
resolveList(itemMap, missingItemLinkListMap, Channel::addLinkedItem); resolveList(itemMap, missingItemLinkListMap, Channel::addLinkedItem);
resolveList(groupMap, missingSubGroupListMap, Group::addGroup); resolveList(groupMap, missingSubGroupListMap, Group::addGroup);
resolveList(itemMap, missingItemListMap, this::addItemToGroup); resolveList(itemMap, missingItemListMap, this::addItemToGroup);
resolveList(channelTypeMap, missingChannelTypeListMap, ThingType::addChannelType); resolveList(channelTypeMap, missingChannelTypeListMap, ThingType::addChannelType);
resolveList(parameterMap, missingParameterListMap, ThingType::addParameter); resolveList(parameterMap, missingParameterListMap, ThingType::addParameter);
resolveList(itemMap, missingControllingListMap, Item::addControlling);
createUnknownGroupIfNecessary(); createUnknownGroupIfNecessary();
createChannelCategories(); createChannelCategories();
createItemCategories(); createItemCategories();
if (checkUnusedElements) { if (checkUnusedElements) {
checkUnusedElements(); checkUnusedElements();
} }
this.root.treeResolveAll(); this.root.treeResolveAll();
this.root.doFullTraversal();
} }
private void addItemToGroup(Group group, Item item) { private void addItemToGroup(Group group, Item item) {
...@@ -226,6 +229,12 @@ public class EraserParserHelper { ...@@ -226,6 +229,12 @@ public class EraserParserHelper {
return thing; return thing;
} }
public FrequencySetting setID(FrequencySetting FrequencySetting, String id) {
FrequencySetting.setID(id);
FrequencySettingMap.put(id,FrequencySetting);
return FrequencySetting;
}
public ThingType setID(ThingType thingType, String id) { public ThingType setID(ThingType thingType, String id) {
thingType.setID(id); thingType.setID(id);
thingTypeMap.put(id, thingType); thingTypeMap.put(id, thingType);
...@@ -259,6 +268,7 @@ public class EraserParserHelper { ...@@ -259,6 +268,7 @@ public class EraserParserHelper {
return c; return c;
} }
public Channel setLinks(Channel c, StringList linkNames) { public Channel setLinks(Channel c, StringList linkNames) {
missingItemLinkListMap.put(c, linkNames); missingItemLinkListMap.put(c, linkNames);
return c; return c;
...@@ -300,6 +310,7 @@ public class EraserParserHelper { ...@@ -300,6 +310,7 @@ public class EraserParserHelper {
itemWithCorrectType.setID(prototype.getID()); itemWithCorrectType.setID(prototype.getID());
itemWithCorrectType.setLabel(prototype.getLabel()); itemWithCorrectType.setLabel(prototype.getLabel());
itemWithCorrectType.setMetaDataList(prototype.getMetaDataList()); itemWithCorrectType.setMetaDataList(prototype.getMetaDataList());
itemWithCorrectType.setFrequencySetting(prototype.getFrequencySetting());
if (!(itemWithCorrectType instanceof ActivityItem)) { if (!(itemWithCorrectType instanceof ActivityItem)) {
String state = prototype.getStateAsString(); String state = prototype.getStateAsString();
itemWithCorrectType.disableSendState(); itemWithCorrectType.disableSendState();
...@@ -312,7 +323,6 @@ public class EraserParserHelper { ...@@ -312,7 +323,6 @@ public class EraserParserHelper {
} }
moveMissingForRetype(itemWithCorrectType, prototype, missingTopicMap); moveMissingForRetype(itemWithCorrectType, prototype, missingTopicMap);
moveMissingForRetype(itemWithCorrectType, prototype, missingControllingListMap);
moveMissingForRetype(itemWithCorrectType, prototype, missingItemCategoryMap); moveMissingForRetype(itemWithCorrectType, prototype, missingItemCategoryMap);
itemMap.put(prototype.getID(), itemWithCorrectType); itemMap.put(prototype.getID(), itemWithCorrectType);
...@@ -470,6 +480,12 @@ public class EraserParserHelper { ...@@ -470,6 +480,12 @@ public class EraserParserHelper {
return result; return result;
} }
public Root createRoot(FrequencySetting FrequencySetting) {
Root result = createRoot();
result.addFrequencySetting(FrequencySetting);
return result;
}
//+++ newStuff (to be categorized) +++ //+++ newStuff (to be categorized) +++
public Designator createDesignator(String itemName) { public Designator createDesignator(String itemName) {
Designator result = new Designator(); Designator result = new Designator();
......
...@@ -250,6 +250,7 @@ public class RulesTest { ...@@ -250,6 +250,7 @@ public class RulesTest {
assertEquals(2, counter.get(item), "Change of item to 7 should not trigger the rule, check2 violated"); assertEquals(2, counter.get(item), "Change of item to 7 should not trigger the rule, check2 violated");
} }
@Test @Test
public void testStateSyncGroupRewriteStructure() { public void testStateSyncGroupRewriteStructure() {
// init StateSyncGroup // init StateSyncGroup
...@@ -915,6 +916,35 @@ public class RulesTest { ...@@ -915,6 +916,35 @@ public class RulesTest {
assertEquals(2, counter.get(null), "Rule was not executed two times"); assertEquals(2, counter.get(null), "Rule was not executed two times");
} }
@Test
public void testFrequencySetting() {
TestUtils.ModelAndItem mai = createModelAndItem(0);
NumberItem numberItem = mai.item;
FrequencySetting itemPerformance = new FrequencySetting();
itemPerformance.setEventProcessingFrequency(10);
numberItem.setFrequencySetting(itemPerformance);
Rule rule = new Rule();
CountingAction counter = new CountingAction();
rule.addAction(counter);
rule.activateFor(numberItem);
numberItem.setState(1);
numberItem.setState(2);
assertEquals(1, counter.get(numberItem), "Action was triggered although FrequencySetting too small");
counter.reset();
waitMillis(100);
numberItem.setState(3);
assertEquals(1, counter.get(numberItem), "Action wasn't triggered although frequency FrequencySetting is small enough");
counter.reset();
numberItem.setState(4);
numberItem.setState(5);
assertEquals(0, counter.get(numberItem), "Action was triggered although FrequencySetting too small");
counter.reset();
}
private static void waitMillis(int millis) { private static void waitMillis(int millis) {
try { try {
Thread.sleep(millis); Thread.sleep(millis);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment