Coverage for tutorials/ngsi_v2/e3_context_entities/e3_context_entities_solution.py: 0%
11 statements
« prev ^ index » next coverage.py v7.10.2, created at 2025-08-05 11:07 +0000
« prev ^ index » next coverage.py v7.10.2, created at 2025-08-05 11:07 +0000
1"""
2# # Exercise 3: Context Entities and Relationships
4# Create a building context entity of type 'Building' according to FIWARE's
5# SmartData Models with the properties: `id`, `type`, `address`, `category`,
6# https://github.com/smart-data-models/dataModel.Building/blob/master/Building/doc/spec.md
8# For the single properties check the "Data Model description of
9# properties" section. The input sections are marked with 'ToDo'
11# #### Steps to complete:
12# 1. Set up the missing parameters in the parameter section
13# 2. Find the Building data model online:
14# https://github.com/smart-data-models/dataModel.Building/blob/master/Building/doc/spec.md
15# 3. Create a `ContextEntity` object for your building
16# 4. Create the required `ContextAttributes` and add them to your building model
17# 5. Create a `ContextBrokerClient` and add post your building to the
18# ContextBroker. Afterwards, check if the Context Broker returns the
19# correct information about your building
20# 6. Create an `opening hours` attribute add them to the server
21# 7. Retrieve the `opening hours`, manipulate them and update the model in the
22# server
23# 8. Repeat the procedure with a thermal zone. Currently, the smart data
24# models hold no definition of a thermal zone. Therefore, we first only add a
25# description attribute.
26# 9. Add a `Relationship` attribute to your thermal zone with the name
27# `refBuilding` and type `Relationship` pointing to your building and post
28# the model to the context broker
29# 10. Add a `Relationship` attribute to your building with name
30# `hasZone` and type `Relationship` pointing to your thermal zone and
31# update the model in the context broker.
32# 11. Update the thermal zone and the building in the context broker
33# 12. Retrieve the data by using query statements for their relationships.
34"""
36# ## Import packages
37import json
38from pathlib import Path
40# filip imports
41from filip.clients.ngsi_v2 import ContextBrokerClient
42from filip.models import FiwareHeader
43from filip.models.ngsi_v2.context import ContextEntity, NamedContextAttribute
44from filip.utils.cleanup import clear_context_broker
45from filip.utils.simple_ql import QueryString
47# ## Parameters
48# ToDo: Enter your context broker host and port, e.g. http://localhost:1026.
49CB_URL = "http://localhost:1026"
51# ToDo: Change the name of your service to something unique. If you run
52# on a shared instance this is very important in order to avoid user
53# collisions. You will use this service through the whole tutorial.
54# If you forget to change it, an error will be raised!
55# FIWARE-Service
56SERVICE = "filip_tutorial"
57# FIWARE-Service path
58SERVICE_PATH = "/"
60# ToDo: Path to json-files to store entity data for follow up exercises,
61# e.g. ../e3_my_entities.json. Files that are used in exercises and files
62# that are used in solutions are different from each other so be careful
63# when working with them. You can of course change the paths as you wish,
64# but it is recommended to use the already given path names.
65WRITE_ENTITIES_FILEPATH = Path("../e3_context_entities_solution_entities.json")
67# ## Main script
68if __name__ == "__main__":
69 # create a fiware header object
70 fiware_header = FiwareHeader(service=SERVICE, service_path=SERVICE_PATH)
71 # clear the state of your service and scope
72 clear_context_broker(url=CB_URL, fiware_header=fiware_header)
74 # Create a context entity for a `building` following the smart data models
75 # specifications
76 building = ContextEntity(id="urn:ngsi-ld:building:001", type="Building")
78 # create the property `category` to your building
79 category = NamedContextAttribute(name="category", type="Array", value=["office"])
81 # ToDo: Create a property `address` for your building. Follow the full yaml
82 # description in the specifications. It reuses the specification from
83 # here: https://schema.org/PostalAddress
84 address = NamedContextAttribute(
85 name="address",
86 type="PostalAddress",
87 value={
88 "addressCountry": "DE",
89 "addressLocality": "Any City",
90 "postalCode": "12345",
91 "streetAddress": "Any Street 5",
92 },
93 )
95 # ToDo: Create a `description` property for your building.
96 building_description = NamedContextAttribute(
97 name="description",
98 type="Text",
99 value="Small office building " "with good insulation " "standard",
100 )
102 # add all properties to your building using the
103 # `add_attribute` function of your building object
104 building.add_attributes(attrs=[building_description, category, address])
106 # ToDo: Create a context broker client and add the fiware_header.
107 cbc = ContextBrokerClient(url=CB_URL, fiware_header=fiware_header)
108 # ToDo: Send your building model to the context broker. Check the client
109 # for proper functioning.
110 cbc.post_entity(entity=building)
112 # Update your local building model with the one from the server
113 building = cbc.get_entity(entity_id=building.id, entity_type=building.type)
115 # print your `building model` as json
116 print(f"This is your building model: \n {building.model_dump_json(indent=2)} \n")
118 # ToDo: Create an `opening hours` property and add it to the building object
119 # in the context broker. Do not update the whole entity! In real
120 # scenarios it might have been modified by other users.
121 opening_hours = NamedContextAttribute(
122 name="openingHours",
123 type="array",
124 value=["Mo-Fr 10:00-19:00", "Sa closed", "Su closed"],
125 )
127 cbc.update_or_append_entity_attributes(
128 entity_id=building.id, entity_type=building.type, attrs=[opening_hours]
129 )
131 # ToDo: Retrieve and print the property `opening hours`.
132 hours = cbc.get_attribute_value(
133 entity_id=building.id, entity_type=building.type, attr_name=opening_hours.name
134 )
135 print(f"Your opening hours: {hours} \n")
137 # ToDo: Modify the property `opening hours` of the building.
138 cbc.update_attribute_value(
139 entity_id=building.id,
140 entity_type=building.type,
141 attr_name=opening_hours.name,
142 value=["Mo-Sa 10:00-19:00", "Su closed"],
143 )
145 # ToDo: At this point you might have already noticed that your local
146 # building model and the building model in the context broker are out of
147 # sync. Hence, synchronize them again!
148 building = cbc.get_entity(entity_id=building.id, entity_type=building.type)
150 # print your building
151 print(f"Your updated building model: \n {building.model_dump_json(indent=2)} \n")
153 # ToDo: Create an entity of the thermal zone and add a description property
154 # to it.
155 thermal_zone = ContextEntity(id="ThermalZone:001", type="ThermalZone")
157 thermal_zone_description = NamedContextAttribute(
158 name="description",
159 type="Text",
160 value="This zones covers " "the entire building",
161 )
162 thermal_zone.add_attributes(attrs=[thermal_zone_description])
164 # ToDo: Create and add a property that references your building model. Use the
165 # `Relationship` for type and `refBuilding` for its name.
166 ref_building = NamedContextAttribute(
167 name="refBuilding", type="Relationship", value=building.id
168 )
169 thermal_zone.add_attributes(attrs=[ref_building])
171 # print all relationships of your thermal zone
172 for relationship in thermal_zone.get_relationships():
173 print(
174 f"Relationship properties of your thermal zone model: \n "
175 f"{relationship.model_dump_json(indent=2)} \n"
176 )
178 # ToDo: Post your thermal zone model to the context broker.
179 cbc.post_entity(entity=thermal_zone)
180 thermal_zone = cbc.get_entity(
181 entity_id=thermal_zone.id, entity_type=thermal_zone.type
182 )
184 # ToDo: Create and add a property that references your thermal zone. Use the
185 # `Relationship` for type and `hasZone` for its name. Make sure that
186 # your local model and the server model are in sync afterwards.
187 ref_zone = NamedContextAttribute(
188 name="hasZone", type="Relationship", value=thermal_zone.id
189 )
190 cbc.update_or_append_entity_attributes(
191 entity_id=building.id, entity_type=building.type, attrs=[ref_zone]
192 )
193 building = cbc.get_entity(entity_id=building.id, entity_type=building.type)
195 # ToDo: Create a filter request that retrieves all entities from the
196 # server that have `refBuilding` attribute that reference your building
197 # by using the FIWARE's simple query language.
198 # `filip.utils.simple_ql` module helps you to validate your query string.
199 # 1. Prepare the query string using the `filip.utils.simple_ql`.
200 # 2. Use the string in a context broker request and retrieve the entities.
201 query = QueryString(qs=("refBuilding", "==", building.id))
202 for entity in cbc.get_entity_list(q=query):
203 print(
204 f"All entities referencing the building: "
205 f"\n {entity.model_dump_json(indent=2)}\n"
206 )
208 # ToDo: Create a filter request that retrieves all entities from the
209 # server that have `hasZone` attribute that reference your thermal zone
210 # by using the FIWARE's simple query language.
211 # `filip.utils.simple_ql` module helps you to validate your query string.
212 # 1. Prepare the query string using the `filip.utils.simple_ql`.
213 # 2. Use the string in a context broker request and retrieve the entities.
214 query = QueryString(qs=("hasZone", "==", thermal_zone.id))
215 for entity in cbc.get_entity_list(q=query):
216 print(
217 f"All entities referencing the thermal zone: "
218 f"\n {entity.model_dump_json(indent=2)} \n"
219 )
221 # write entities to file and clear server state
222 assert (
223 WRITE_ENTITIES_FILEPATH.suffix == ".json"
224 ), f"Wrong file extension! {WRITE_ENTITIES_FILEPATH.suffix}"
225 WRITE_ENTITIES_FILEPATH.touch(exist_ok=True)
226 with WRITE_ENTITIES_FILEPATH.open("w", encoding="utf-8") as f:
227 entities = [item.model_dump() for item in cbc.get_entity_list()]
228 json.dump(entities, f, ensure_ascii=False, indent=2)
230 clear_context_broker(url=CB_URL, fiware_header=fiware_header)