diff --git a/examples/area_goals/model.goal b/examples/area_goals/model.goal index e69de29..c8eb4b9 100644 --- a/examples/area_goals/model.goal +++ b/examples/area_goals/model.goal @@ -0,0 +1,29 @@ +Broker HomeMQTT + host: 'localhost' + port: 1883 + auth: + username: '' + password: '' +end + +Entity Robot1Pose + type: sensor + topic: 'robot_a.pose' + source: HomeMQTT + attributes: + - position: dict + - orientation: dict +end + +Goal Goal_1 + bottomLeftEdge: Point3D(5, 5, 0) + lengthX: 2 + lengthY: 2 + tag: ENTER +end + +Scenario MyScenario + goals: + - Goal_1 + concurrent: False +end diff --git a/examples/entity_goals/scenario.goal b/examples/entity_goals/scenario.goal index adbd684..18de675 100644 --- a/examples/entity_goals/scenario.goal +++ b/examples/entity_goals/scenario.goal @@ -43,18 +43,32 @@ Goal Goal_1 entity: TempSensor1 end +Goal Goal_2 + condition: + AirQualitySensor1.gas <= 25 +end + +/* +Goal Goal_3 + condition: + mean(AirQualitySensor1.gas, 10) <= 25 +end +*/ + +/* Goal Goal_2 condition: (mean(AirQualitySensor1.gas, 10) <= 25) and (std(AirQualitySensor1.humidity, 10) < 0.5) end +*/ Goal Goal_3 condition: - (TempSensor1.temp * 10 > 10) and - (TempSensor2.temp + 2 > 10) and - (TempSensor3.temp - TempSensor2.temp > 10) + (TempSensor1.temp > 10) and + (TempSensor2.temp > 10) and + (TempSensor3.temp - TempSensor2.temp < 10) end diff --git a/goal_dsl/codegen.py b/goal_dsl/codegen.py index 2215730..247b8ec 100644 --- a/goal_dsl/codegen.py +++ b/goal_dsl/codegen.py @@ -65,7 +65,7 @@ def process_goals(goals): if goal.__class__.__name__ == 'EntityStateConditionGoal': # cond_lambda = make_condition_lambda(goal.condition) cond_lambda = goal.condition.cond_expr - goal.cond_lambda = goal.condition.cond_expr + goal.condition.cond_lambda = goal.condition.cond_expr elif goal.__class__.__name__ == 'EntityStateChangeGoal': pass elif goal.__class__.__name__ == 'ComplexGoal': @@ -109,7 +109,6 @@ def goal_max_min_duration_from_tc(goal): def make_condition_lambda(condition): cond = Condition(condition) cond.build() - print(cond.cond_expr) return cond.cond_expr diff --git a/goal_dsl/grammar/area_goals.tx b/goal_dsl/grammar/area_goals.tx index 97c9710..467d34e 100644 --- a/goal_dsl/grammar/area_goals.tx +++ b/goal_dsl/grammar/area_goals.tx @@ -16,7 +16,7 @@ AreaGoal: RectangleAreaGoal: 'Goal' name=ID ( - ('entity:' entity=[Entity:FQN|+pm:entities*]) + //('entity:' entity=[Entity:FQN|+pm:entities*]) ('bottomLeftEdge:' bottomLeftEdge=Point ) ('lengthX:' lengthX=NUMBER ) ('lengthY:' lengthY=NUMBER ) @@ -51,7 +51,7 @@ MovingAreaGoal: CircularAreaGoal: 'Goal' name=ID ( - ('entity:' entity=[Entity:FQN|+pm:entities*]) + //('entity:' entity=[Entity:FQN|+pm:entities*]) ('center:' center=Point) ('radius:' radius=NUMBER) ('tag:' type=AreaGoalTag) diff --git a/goal_dsl/language.py b/goal_dsl/language.py index 3783cda..c6c3326 100644 --- a/goal_dsl/language.py +++ b/goal_dsl/language.py @@ -110,9 +110,7 @@ def model_proc(model, metamodel): def condition_processor(cond): # Adds a cond.cond_expr property to the Condition instance - print("AAAAAS") build_cond_expr(cond) - print(cond.cond_expr) def nid_processor(nid): @@ -232,6 +230,8 @@ def transform_cond(cond): cond.cond_expr = cond.cond_expr.replace("condition:", "") if cond.cond_expr.startswith(" "): cond.cond_expr = cond.cond_expr[1:] + if "mean" in cond.cond_expr: + pass def is_float(string): @@ -258,3 +258,9 @@ def get_cond_definition(cond): def goaldsl_language(): "Goal-driven CPS Behavior Verification language" return get_metamodel() + + +def get_model_grammar(model_path): + mm = get_metamodel() + grammar_model = mm.grammar_model_from_file(model_path) + return grammar_model diff --git a/goal_dsl/logging.py b/goal_dsl/logging.py new file mode 100644 index 0000000..3bacdb6 --- /dev/null +++ b/goal_dsl/logging.py @@ -0,0 +1,12 @@ +import logging +import os +from rich.logging import RichHandler + +LOGGING_FORMAT = "%(message)s" +LOG_LEVEL = os.getenv("GOALDSL_LOG_LEVEL", "INFO") + +logging.basicConfig( + level=LOG_LEVEL, format=LOGGING_FORMAT, datefmt="[%X]", handlers=[RichHandler()] +) + +default_logger = logging.getLogger() diff --git a/goal_dsl/templates/scenario.tpl b/goal_dsl/templates/scenario.tpl index 760460d..c7cac7c 100755 --- a/goal_dsl/templates/scenario.tpl +++ b/goal_dsl/templates/scenario.tpl @@ -1,24 +1,17 @@ #!/usr/bin/env python3 -from goalee import Scenario, Redisbroker, MQTTBroker, AMQPBroker -from goalee.entity_goals import ( - EntityStateChangeGoal, EntityStateConditionGoal -) +from goalee import Scenario, RedisBroker, MQTTBroker, AMQPBroker from goalee.entity import Entity from goalee.area_goals import * from goalee.complex_goal import * from goalee.types import Point +from goalee.entity_goals import ( + EntityStateChange, + EntityStateCondition +) - -{% if broker.__class__.__name__ == 'AMQPBroker' %} -broker = AMQPBroker() -{% elif broker.__class__.__name__ == 'RedisBroker' %} -broker = RedisBroker() -{% elif broker.__class__.__name__ == 'MQTTBroker' %} -broker = MQTTBroker() -{% endif %} - +entities_list = [] {% for entity in entities %} {{ entity.name }} = Entity( @@ -26,12 +19,61 @@ broker = MQTTBroker() etype='{{ entity.etype }}', topic='{{ entity.topic }}', attributes={{ entity.attr_list }}, - # broker=broker + {% if entity.source.ref.__class__.__name__ == 'AMQPBroker' %} + source=AMQPBroker( + host='{{ entity.source.ref.host }}', + port={{ entity.source.ref.port }}, + username='{{ entity.source.ref.username }}', + password='{{ entity.source.ref.password }}', + vhost='{{ entity.source.ref.vhost }}', + ) + {% elif entity.source.ref.__class__.__name__ == 'RedisBroker' %} + source=RedisBroker( + host='{{ entity.source.ref.host }}', + port={{ entity.source.ref.port }}, + db={{ entity.source.ref.db }}, # default DB number is 0 + username='{{ entity.source.ref.username }}', + password='{{ entity.source.ref.password }}', + ) + {% elif entity.source.ref.__class__.__name__ == 'MQTTBroker' %} + source=MQTTBroker( + host='{{ entity.source.ref.host }}', + port={{ entity.source.ref.port }}, + username='{{ entity.source.ref.username }}', + password='{{ entity.source.ref.password }}', + ) + {% endif %} ) + +entities_list.append({{ entity.name }}) {% endfor %} if __name__ == '__main__': + {% if scenario.broker.__class__.__name__ == 'AMQPBroker' %} + broker = AMQPBroker( + host='{{ scenario.broker.host }}', + port={{ scenario.broker.port }}, + username='{{ scenario.broker.username }}', + password='{{ scenario.broker.password }}', + vhost='{{ scenario.broker.vhost }}', + ) + {% elif scenario.broker.__class__.__name__ == 'RedisBroker' %} + broker = RedisBroker( + host='{{ scenario.broker.host }}', + port={{ scenario.broker.port }}, + db={{ scenario.broker.db }}, # default DB number is 0 + username='{{ scenario.broker.username }}', + password='{{ scenario.broker.password }}', + ) + {% elif scenario.broker.__class__.__name__ == 'MQTTBroker' %} + broker = MQTTBroker( + host='{{ scenario.broker.host }}', + port={{ scenario.broker.port }}, + username='{{ scenario.broker.username }}', + password='{{ scenario.broker.password }}', + ) + {% endif %} t = Scenario( name='{{ scenario.name }}', broker=broker, @@ -40,18 +82,21 @@ if __name__ == '__main__': {% for goal in goals %} {% if goal.__class__.__name__ == 'EntityStateConditionGoal' %} - g = EntityStateConditionGoal( + g = EntityStateCondition( name='{{ goal.name }}', - entities={{ entity_names }}, - condition=lambda entities: {{goal.cond_lambda}}, - duration=({{ goal.min_duration }}, {{ goal.max_duration }}), + entities=[{% for e in entity_names %}{{ e }}, {% endfor %}], + # condition=lambda entities: True if {{goal.cond_lambda}} else False, + condition='{{ goal.condition.cond_expr.replace("'", "\"") }}', + max_duration={{ goal.max_duration }}, + min_duration={{ goal.min_duration }}, ) {% elif goal.__class__.__name__ == 'EntityStateChangeGoal' %} - g = EntityStateChangeGoal( - topic='{{ goal.entity.topic }}', + g = EntityStateChange( + entity={{ goal.entity.name }}, name='{{ goal.name }}', - duration=({{ goal.min_duration }}, {{ goal.max_duration }}), + max_duration={{ goal.max_duration }}, + min_duration={{ goal.min_duration }}, ) {% elif goal.__class__.__name__ == 'WaypointTrajectoryGoal' %} g = WaypointTrajectoryGoal( @@ -64,6 +109,27 @@ if __name__ == '__main__': deviation={{ goal.maxDeviation }}, duration=({{ goal.min_duration }}, {{ goal.max_duration }}), ) + {% elif goal.__class__.__name__ == 'RectangleAreaGoal' %} + g = RectangleAreaGoal( + name='{{ goal.name }}', + entities=[{% for e in entity_names %}{{ e }}, {% endfor %}], + bottom_left_edge={{ goal.bottom_left_edge}}, + length_x={{ goal.lengthX}}, + length_y={{ goal.lengthY}}, + tag=AreaGoalTag.{{ goal.tag }}, + max_duration={{ goal.max_duration }}, + min_duration={{ goal.min_duration }}, + ) + {% elif goal.__class__.__name__ == 'CircularAreaGoal' %} + g = CircularAreaGoal( + name='{{ goal.name }}', + entities=[{% for e in entity_names %}{{ e }}, {% endfor %}], + center={{ goal.center }}, + radius={{ goal.radius }}, + tag=AreaGoalTag.{{ goal.tag }}, + max_duration={{ goal.max_duration }}, + min_duration={{ goal.min_duration }}, + ) {% elif goal.__class__.__name__ == 'PositionGoal' %} g = PositionGoal( topic='{{ goal.entity.topic }}', @@ -80,8 +146,8 @@ if __name__ == '__main__': {% endif %} duration=({{ goal.min_duration }}, {{ goal.max_duration }}), ) - {% for goal in goal.goals %} - {% if goal.__class__.__name__ == 'EntityStateConditionGoal' %} + {% for goal in goal.goals %} + {% if goal.__class__.__name__ == 'EntityStateConditionGoal' %} g = EntityStateConditionGoal( condition="{{goal.cond_lambda}}", duration=({{ goal.min_duration }}, {{ goal.max_duration }}), @@ -103,12 +169,12 @@ if __name__ == '__main__': deviation={{ goal.maxDeviation }}, duration=({{ goal.min_duration }}, {{ goal.max_duration }}), ) - {% endif %} - cg.add_goal(g) - {% endfor %} + {% endif %} + cg.add_goal(cg) + {% endfor %} ## More Goals to Generate here {% endif %} - t.add_goal(cg) + t.add_goal(g) {% endfor %} {% if scenario.concurrent == True %} diff --git a/goal_dsl/utils.py b/goal_dsl/utils.py index e69de29..0847e69 100644 --- a/goal_dsl/utils.py +++ b/goal_dsl/utils.py @@ -0,0 +1,14 @@ +import time + + +def gen_timestamp() -> int: + """gen_timestamp. + Generate a timestamp. + + Args: + + Returns: + int: Timestamp in integer representation. User `str()` to + transform to string. + """ + return int(time.time_ns() * 1e6)