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

1""" 

2# # Exercise 3: Context Entities and Relationships 

3 

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 

7 

8# For the single properties check the "Data Model description of 

9# properties" section. The input sections are marked with 'ToDo' 

10 

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""" 

35 

36# ## Import packages 

37import json 

38from pathlib import Path 

39 

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 

46 

47# ## Parameters 

48# ToDo: Enter your context broker host and port, e.g. http://localhost:1026. 

49CB_URL = "http://localhost:1026" 

50 

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 = "/" 

59 

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") 

66 

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) 

73 

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") 

77 

78 # create the property `category` to your building 

79 category = NamedContextAttribute(name="category", type="Array", value=["office"]) 

80 

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 ) 

94 

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 ) 

101 

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]) 

105 

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) 

111 

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) 

114 

115 # print your `building model` as json 

116 print(f"This is your building model: \n {building.model_dump_json(indent=2)} \n") 

117 

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 ) 

126 

127 cbc.update_or_append_entity_attributes( 

128 entity_id=building.id, entity_type=building.type, attrs=[opening_hours] 

129 ) 

130 

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") 

136 

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 ) 

144 

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) 

149 

150 # print your building 

151 print(f"Your updated building model: \n {building.model_dump_json(indent=2)} \n") 

152 

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") 

156 

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]) 

163 

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]) 

170 

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 ) 

177 

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 ) 

183 

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) 

194 

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 ) 

207 

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 ) 

220 

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) 

229 

230 clear_context_broker(url=CB_URL, fiware_header=fiware_header)