def create_entities() -> List[ContextEntity]: """ Create entities with random values Returns: """ def create_attr(): return { 'temperature': { 'value': random(), 'type': 'Number' }, 'humidity': { 'value': random(), 'type': 'Number' }, 'co2': { 'value': random(), 'type': 'Number' } } return [ ContextEntity(id='Kitchen', type='Room', **create_attr()), ContextEntity(id='LivingRoom', type='Room', **create_attr()) ]
def load(self, json_string: str, semantic_manager: 'SemanticsManager'): """ Load the state of the registry out of a json string. The current state will be discarded Args: json_string (str): State expressed as json string semantic_manager (SemanticsManager): manager to which registry belongs Returns: None """ self.clear() save = json.loads(json_string) for instance_dict in save['instances']: entity_json = instance_dict['entity'] header = InstanceHeader.parse_raw(instance_dict['header']) context_entity = ContextEntity.parse_raw(entity_json) instance = semantic_manager._context_entity_to_semantic_class( context_entity, header) if instance_dict['old_state'] is not None: instance.old_state.state = \ ContextEntity.parse_raw(instance_dict['old_state']) self._registry[instance.get_identifier()] = instance for identifier in save['deleted_identifiers']: self._deleted_identifiers.append( InstanceIdentifier.parse_raw(identifier))
def build_context_entity_from_device(device: Device) -> ContextEntity: from filip.models.base import DataType entity = ContextEntity(id=device.entity_name, type=device.entity_type) for command in device.commands: entity.add_attributes([ # Command attribute will be registered by the device_update NamedContextAttribute(name=f"{command.name}_info", type=DataType.COMMAND_RESULT), NamedContextAttribute(name=f"{command.name}_status", type=DataType.COMMAND_STATUS) ]) for attribute in device.attributes: entity.add_attributes([ NamedContextAttribute(name=attribute.name, type=DataType.STRUCTUREDVALUE, metadata=attribute.metadata) ]) for static_attribute in device.static_attributes: entity.add_attributes([ NamedContextAttribute(name=static_attribute.name, type=static_attribute.type, value=static_attribute.value, metadata=static_attribute.metadata) ]) return entity
def test_entity_filtering(self): """ Test filter operations of context broker client """ with ContextBrokerClient( url=settings.CB_URL, fiware_header=self.fiware_header) as client: # test patterns with self.assertRaises(ValueError): client.get_entity_list(id_pattern='(&()?') with self.assertRaises(ValueError): client.get_entity_list(type_pattern='(&()?') entities_a = [ContextEntity(id=str(i), type=f'filip:object:TypeA') for i in range(0, 5)] client.update(action_type=ActionType.APPEND, entities=entities_a) entities_b = [ContextEntity(id=str(i), type=f'filip:object:TypeB') for i in range(6, 10)] client.update(action_type=ActionType.APPEND, entities=entities_b) entities_all = client.get_entity_list() entities_by_id_pattern = client.get_entity_list( id_pattern='.*[1-5]') self.assertLess(len(entities_by_id_pattern), len(entities_all)) entities_by_type_pattern = client.get_entity_list( type_pattern=".*TypeA$") self.assertLess(len(entities_by_type_pattern), len(entities_all)) qs = QueryString(qs=[('presentValue', '>', 0)]) entities_by_query = client.get_entity_list(q=qs) self.assertLess(len(entities_by_query), len(entities_all)) # test options for opt in list(AttrsFormat): entities_by_option = client.get_entity_list(response_format=opt) self.assertEqual(len(entities_by_option), len(entities_all)) self.assertEqual(client.get_entity( entity_id='0', response_format=opt), entities_by_option[0]) with self.assertRaises(ValueError): client.get_entity_list(response_format='not in AttrFormat') client.update(action_type=ActionType.DELETE, entities=entities_a) client.update(action_type=ActionType.DELETE, entities=entities_b)
def setUp(self) -> None: """ Setup test data Returns: None """ self.fiware_header = FiwareHeader( service=settings.FIWARE_SERVICE, service_path=settings.FIWARE_SERVICEPATH) clear_all(fiware_header=self.fiware_header, cb_url=settings.CB_URL, iota_url=settings.IOTA_JSON_URL) self.resources = { "entities_url": "/v2/entities", "types_url": "/v2/types", "subscriptions_url": "/v2/subscriptions", "registrations_url": "/v2/registrations" } self.attr = {'temperature': {'value': 20.0, 'type': 'Number'}} self.entity = ContextEntity(id='MyId', type='MyType', **self.attr) self.client = ContextBrokerClient( url=settings.CB_URL, fiware_header=self.fiware_header) self.subscription = Subscription.parse_obj({ "description": "One subscription to rule them all", "subject": { "entities": [ { "idPattern": ".*", "type": "Room" } ], "condition": { "attrs": [ "temperature" ], "expression": { "q": "temperature>40" } } }, "notification": { "http": { "url": "http://localhost:1234" }, "attrs": [ "temperature", "humidity" ] }, "expires": datetime.now(), "throttling": 0 })
def test_pagination(self): """ Test pagination of context broker client Test pagination. only works if enough entities are available """ with ContextBrokerClient( url=settings.CB_URL, fiware_header=self.fiware_header) as client: entities_a = [ContextEntity(id=str(i), type=f'filip:object:TypeA') for i in range(0, 1000)] client.update(action_type=ActionType.APPEND, entities=entities_a) entities_b = [ContextEntity(id=str(i), type=f'filip:object:TypeB') for i in range(1000, 2001)] client.update(action_type=ActionType.APPEND, entities=entities_b) self.assertLessEqual(len(client.get_entity_list(limit=1)), 1) self.assertLessEqual(len(client.get_entity_list(limit=999)), 999) self.assertLessEqual(len(client.get_entity_list(limit=1001)), 1001) self.assertLessEqual(len(client.get_entity_list(limit=2001)), 2001)
def create_entity(self): """Creates entitiy of PID controller in orion context broker""" try: self.ORION_CB.get_entity(entity_id=self.params['controller_name'], entity_type=self.params['type']) print('Entity name already assigned') except requests.exceptions.HTTPError as err: msg = err.args[0] if "NOT FOUND" not in msg.upper(): raise # throw other errors except "entity not found" print('[INFO]: Create new PID entity') pid_entity = ContextEntity(id=f"{self.params['controller_name']}", type=self.params['type']) cb_attrs = [] for attr in ['Kp', 'Ki', 'Kd', 'lim_low', 'lim_upper', 'setpoint']: cb_attrs.append( NamedContextAttribute(name=attr, type="Number", value=self.params[attr])) pid_entity.add_attributes(attrs=cb_attrs) self.ORION_CB.post_entity(entity=pid_entity, update=True)
def test_batch_operations(self): """ Test batch operations of context broker client """ with ContextBrokerClient( url=settings.CB_URL, fiware_header=self.fiware_header) as client: entities = [ContextEntity(id=str(i), type=f'filip:object:TypeA') for i in range(0, 1000)] client.update(entities=entities, action_type=ActionType.APPEND) entities = [ContextEntity(id=str(i), type=f'filip:object:TypeB') for i in range(0, 1000)] client.update(entities=entities, action_type=ActionType.APPEND) entity = EntityPattern(idPattern=".*", typePattern=".*TypeA$") query = Query.parse_obj( {"entities": [entity.dict(exclude_unset=True)]}) self.assertEqual(1000, len(client.query(query=query, response_format='keyValues')))
def test_fiware_header(self): """ Test for fiware header """ header = FiwareHeader.parse_obj(self.fiware_header) self.assertEqual(header.dict(by_alias=True), self.fiware_header) self.assertEqual(header.json(by_alias=True), json.dumps(self.fiware_header)) self.assertRaises(ValidationError, FiwareHeader, service='jkgsadh ', service_path='/testing') self.assertRaises(ValidationError, FiwareHeader, service='%', service_path='/testing') self.assertRaises(ValidationError, FiwareHeader, service='filip', service_path='testing/') self.assertRaises(ValidationError, FiwareHeader, service='filip', service_path='/$testing') self.assertRaises(ValidationError, FiwareHeader, service='filip', service_path='/testing ') self.assertRaises(ValidationError, FiwareHeader, service='filip', service_path='#') headers = FiwareHeader.parse_obj(self.fiware_header) with ContextBrokerClient(url=settings.CB_URL, fiware_header=headers) as client: entity = ContextEntity(id='myId', type='MyType') for path in self.service_paths: client.fiware_service_path = path client.post_entity(entity=entity) client.get_entity(entity_id=entity.id) client.fiware_service_path = '/#' self.assertGreaterEqual(len(client.get_entity_list()), len(self.service_paths)) for path in self.service_paths: client.fiware_service_path = path client.delete_entity(entity_id=entity.id, entity_type=entity.type)
def test(dictionary: Dict): # either the assignment throws an error or # the entity can get posted and gets found assignment_error = False try: entity = ContextEntity(**dictionary) except: assignment_error = True self.assertFalse(needs_to_succeed) if not assignment_error: client.post_entity(entity=entity) # if post successful get will not throw an # error client.get_entity(entity_id=entity.id, entity_type=entity.type) client.delete_entity(entity_id=entity.id, entity_type=entity.type)
"type": "Store", "id": "urn:ngsi-ld:Store:002", "address": { "type": "Text", "value": "Friedrichstraße 44" }, "location": { "type": "Text", "value": "[13.3903, 52.5075]" }, "name": { "type": "Text", "value": "Checkpoint Markt" } }] store_entities = [ContextEntity(**store) for store in store_dict] for entity in store_entities: cb_client.post_entity(entity) # ## 1.2 Product entities # with ContextBrokerClient(fiware_header=fiware_header) as cb_client: product_dict = [ { "id": "urn:ngsi-ld:Product:001", "type": "Product", "name": { "type": "Text", "value": "Beer" }, "size": { "type": "Text", "value": "S" },
fiware_header = FiwareHeader(service=SERVICE, service_path=SERVICE_PATH) cb_client = ContextBrokerClient(url=CB_URL, fiware_header=fiware_header) room_001 = { "id": "urn:ngsi-ld:Room:001", "type": "Room", "temperature": { "value": 11, "type": "Float" }, "pressure": { "value": 111, "type": "Integer" } } room_entity = ContextEntity(**room_001) cb_client.post_entity(entity=room_entity) # # 2 Setup a subscription and MQTT notifications # # Create the data for the subscription. Have a look at the condition and # the attribute section. Only a change of the temperature attribute will # trigger the subscription and only temperature data will be included # into the message. # Additionally, you should be aware of the throttling and expiration of a # subscription. # # For more details on subscription you might want to # check the Subscription model or the official tutorials. sub_example = { "description": "Subscription to receive MQTT-Notifications about "
def test_patch_entity(self) -> None: """ Test the methode: patch_entity Returns: None """ # setup test-entity entity = ContextEntity(id="test_id1", type="test_type1") attr1 = NamedContextAttribute(name="attr1", value="1") attr1.metadata["m1"] = \ NamedMetadata(name="meta1", type="metatype", value="2") attr2 = NamedContextAttribute(name="attr2", value="2") attr1.metadata["m2"] = \ NamedMetadata(name="meta2", type="metatype", value="3") entity.add_attributes([attr1, attr2]) # sub-Test1: Post new self.client.patch_entity(entity=entity) self.assertEqual(entity, self.client.get_entity(entity_id=entity.id)) self.tearDown() # sub-Test2: ID/type of old_entity changed self.client.post_entity(entity=entity) test_entity = ContextEntity(id="newID", type="newType") test_entity.add_attributes([attr1, attr2]) self.client.patch_entity(test_entity, old_entity=entity) self.assertEqual(test_entity, self.client.get_entity(entity_id=test_entity.id)) self.assertRaises(RequestException, self.client.get_entity, entity_id=entity.id) self.tearDown() # sub-Test3: a non valid old_entity is provided, entity exists self.client.post_entity(entity=entity) old_entity = ContextEntity(id="newID", type="newType") self.client.patch_entity(entity, old_entity=old_entity) self.assertEqual(entity, self.client.get_entity(entity_id=entity.id)) self.tearDown() # sub-Test4: no old_entity provided, entity is new old_entity = ContextEntity(id="newID", type="newType") self.client.patch_entity(entity, old_entity=old_entity) self.assertEqual(entity, self.client.get_entity(entity_id=entity.id)) self.tearDown() # sub-Test5: no old_entity provided, entity is new old_entity = ContextEntity(id="newID", type="newType") self.client.patch_entity(entity, old_entity=old_entity) self.assertEqual(entity, self.client.get_entity(entity_id=entity.id)) self.tearDown() # sub-Test6: New attr, attr del, and attr changed. No Old_entity given self.client.post_entity(entity=entity) test_entity = ContextEntity(id="test_id1", type="test_type1") attr1_changed = NamedContextAttribute(name="attr1", value="2") attr1_changed.metadata["m4"] = \ NamedMetadata(name="meta3", type="metatype5", value="4") attr3 = NamedContextAttribute(name="attr3", value="3") test_entity.add_attributes([attr1_changed, attr3]) self.client.patch_entity(test_entity) self.assertEqual(test_entity, self.client.get_entity(entity_id=entity.id)) self.tearDown() # sub-Test7: Attr changes, concurrent changes in Fiware, # old_entity given self.client.post_entity(entity=entity) concurrent_entity = ContextEntity(id="test_id1", type="test_type1") attr1_changed = copy.deepcopy(attr1) attr1_changed.metadata["m1"].value = "3" attr1_changed.value = "4" concurrent_entity.add_attributes([attr1_changed, attr2]) self.client.patch_entity(concurrent_entity) user_entity = copy.deepcopy(entity) attr3 = NamedContextAttribute(name="attr3", value="3") user_entity.add_attributes([attr3]) self.client.patch_entity(user_entity, old_entity=entity) result_entity = concurrent_entity result_entity.add_attributes([attr2, attr3]) self.assertEqual(result_entity, self.client.get_entity(entity_id=entity.id)) self.tearDown()
def test_mqtt_subscriptions(self): mqtt_url = settings.MQTT_BROKER_URL mqtt_topic = ''.join([settings.FIWARE_SERVICE, settings.FIWARE_SERVICEPATH]) notification = self.subscription.notification.copy( update={'http': None, 'mqtt': Mqtt(url=mqtt_url, topic=mqtt_topic)}) subscription = self.subscription.copy( update={'notification': notification, 'description': 'MQTT test subscription', 'expires': None}) entity = ContextEntity(id='myID', type='Room', **self.attr) self.client.post_entity(entity=entity) sub_id = self.client.post_subscription(subscription) sub_message = None def on_connect(client, userdata, flags, reasonCode, properties=None): if reasonCode != 0: logger.error(f"Connection failed with error code: " f"'{reasonCode}'") raise ConnectionError else: logger.info("Successfully, connected with result code " + str( reasonCode)) client.subscribe(mqtt_topic) def on_subscribe(client, userdata, mid, granted_qos, properties=None): logger.info("Successfully subscribed to with QoS: %s", granted_qos) def on_message(client, userdata, msg): logger.info(msg.topic + " " + str(msg.payload)) nonlocal sub_message sub_message = Message.parse_raw(msg.payload) def on_disconnect(client, userdata, reasonCode, properties=None): logger.info("MQTT client disconnected with reasonCode " + str(reasonCode)) import paho.mqtt.client as mqtt mqtt_client = mqtt.Client(userdata=None, protocol=mqtt.MQTTv5, transport="tcp") # add our callbacks to the client mqtt_client.on_connect = on_connect mqtt_client.on_subscribe = on_subscribe mqtt_client.on_message = on_message mqtt_client.on_disconnect = on_disconnect # connect to the server mqtt_url = urlparse(mqtt_url) mqtt_client.connect(host=mqtt_url.hostname, port=mqtt_url.port, keepalive=60, bind_address="", bind_port=0, clean_start=mqtt.MQTT_CLEAN_START_FIRST_ONLY, properties=None) # create a non-blocking thread for mqtt communication mqtt_client.loop_start() new_value = 50 self.client.update_attribute_value(entity_id=entity.id, attr_name='temperature', value=new_value, entity_type=entity.type) time.sleep(5) # test if the subscriptions arrives and the content aligns with updates self.assertIsNotNone(sub_message) self.assertEqual(sub_id, sub_message.subscriptionId) self.assertEqual(new_value, sub_message.data[0].temperature.value) mqtt_client.loop_stop() mqtt_client.disconnect() time.sleep(1)
# # 1 Creating models # # Create a building with a weather station as context provider # We start from the meta data here. The other way round is also possible but # using the api of the Context Entity Model # Create unit metadata for the temperature sensor of the weather station temperature_metadata = NamedMetadata(name="unit", value=Unit(name="degree Celsius").dict()) # create the temperature attribute of the weather station temperature = ContextAttribute(type="Number", value=20.5, metadata=temperature_metadata) # create the complete model of the building with the weather station weather_station = ContextEntity(id="urn:ngsi-ld:WeatherStation:001", type="WeatherStation", temperature=temperature) # print complete weather station object print("+"*80) print("Building with weather station with one property from a sensor") print("+"*80) print(weather_station.json(indent=2)) # create additional properties of the weather station windspeed_metadata = NamedMetadata(name="unit", type="Unit", value=Unit(name="kilometre per " "hour").dict()) # create the temperature attribute of the weather station windspeed = ContextAttribute(type="Number",
# ## 2 Interact with QL # # ### 2.1 Create a ContextEntity to work with # # for more details see: e01_ngsi_v2_context_basics.py hall = { "id": "Hall_1", "type": "Room", "temperature": { "value": random.randint(0, 100), "type": "Integer" }, } hall_entity = ContextEntity(**hall) cb_client.post_entity(hall_entity) # ### 2.2 Manage subscriptions # # create a subscription # Note: that the IP must be the ones that orion and quantumleap can access, # e.g. service name or static IP, localhost will not work here. ql_client.post_subscription(entity_id=hall_entity.id, cb_url="http://orion:1026", ql_url="http://quantumleap:8668", throttling=0) # Get all subscriptions subscription_list = cb_client.get_subscription_list()
# # ### 2.1.1 Passing a dict: # room1 = { "id": "Room1", "type": "Room", "temperature": { "value": 11, "type": "Float" }, "pressure": { "value": 111, "type": "Integer" } } room1_entity = ContextEntity(**room1) # ### 2.1.2 Using the constructor and interfaces # room2_entity = ContextEntity(id="Room2", type="Room") temp_attr = NamedContextAttribute(name="temperature", value=22, type=DataType.FLOAT) pressure_attr = NamedContextAttribute(name="pressure", value=222, type="Integer") room2_entity.add_attributes([temp_attr, pressure_attr]) # ## 2.2 Post Entities # print(cb_client.get_entity_list())
SERVICE_PATH = '/<your_path>' # ToDo: Path to json-files to store entity data for follow up exercises, # e.g. ./e3_my_entities.json WRITE_ENTITIES_FILEPATH = Path("") # ## Main script if __name__ == '__main__': # create a fiware header object fiware_header = FiwareHeader(service=SERVICE, service_path=SERVICE_PATH) # clear the state of your service and scope clear_context_broker(url=CB_URL, fiware_header=fiware_header) # Create a context entity for a `building` following the smart data models # specifications building = ContextEntity(id="urn:ngsi-ld:building:001", type="Building") # create the property `category` to your building category = NamedContextAttribute(name="category", type="Array", value=["office"]) # ToDo: create a property `address` for your building. Follow the full yaml # description in the specifications. It reuses the specification from # here: https://schema.org/PostalAddress address = NamedContextAttribute(name="address", type="PostalAddress", value={...}) # ToDo: create a `description` property for your building building_description = NamedContextAttribute(...)
def _context_entity_to_semantic_class( self, entity: ContextEntity, header: InstanceHeader) -> SemanticClass: """Converts a ContextEntity to a SemanticClass Args: entity (ContextEntity): entity to convert header (InstanceHeader): Header of the new instance Returns: SemanticClass or SemanticDeviceClass """ class_name = entity.type class_: Type = self.get_class_by_name(class_name) if not self.is_class_name_an_device_class(class_name): loaded_class: SemanticClass = class_(id=entity.id, header=header, enforce_new=True) else: loaded_class: SemanticDeviceClass = class_(id=entity.id, header=header, enforce_new=True) loaded_class.old_state.state = entity # load values of class from the context_entity into the instance for field in loaded_class.get_fields(): field.clear() # remove default values, from hasValue relations field_name = field.name entity_attribute = entity.get_attribute(field_name) if entity_attribute is None: raise Exception( f"The corresponding entity for ({entity.id},{entity.type}) " f"in Fiware misses a field that " f"is required by the class_model: {field_name}. The " f"fiware state and the used vocabulary models are not " f"compatible") entity_field_value = entity.get_attribute(field_name).value if isinstance(entity_field_value, List): values = entity_field_value else: values = [entity_field_value] for value in values: converted_value = self._convert_value_fitting_for_field( field, value) if isinstance(field, RelationField): # we need to bypass the main setter, as it expects an # instance and we do not want to load the instance if it # is not used field._set.add(converted_value) else: field.add(converted_value) # load references into instance references_attribute = entity.get_attribute("referencedBy") references = references_attribute.value for identifier_str, prop_list in references.items(): for prop in prop_list: loaded_class.add_reference( InstanceIdentifier.parse_raw( identifier_str.replace("---", ".")), prop) # load metadata metadata_dict = entity.get_attribute("metadata").value loaded_class.metadata.name = metadata_dict['name'] loaded_class.metadata.comment = metadata_dict['comment'] # load device_settings into instance, if instance is a device if isinstance(loaded_class, SemanticDeviceClass): settings_attribute = entity.get_attribute("deviceSettings") device_settings = DeviceSettings.parse_obj( settings_attribute.value) for key, value in device_settings.dict().items(): loaded_class.device_settings.__setattr__(key, value) return loaded_class