Coverage for tutorials/ngsi_v2/e8_multientity_and_expression_language/e8_multientity_and_expression_language_solution.py: 0%

16 statements  

« prev     ^ index     » next       coverage.py v7.10.2, created at 2025-08-05 11:07 +0000

1""" 

2# # Exercise 8: MultiEntity and Expression Language 

3 

4# The MultiEntity plugin allows the devices provisioned in the IoTAgent to map their 

5attributes to more than one entity, declaring the target entity through the 

6Configuration or Device provisioning APIs. 

7 

8# The IoTAgent Library provides an expression language for measurement transformation, 

9that can be used to adapt the # information coming from the South Bound APIs to the 

10information reported to the Context Broker. This is really useful when you need to 

11adapt measure. 

12 

13# There are available two different expression languages jexl and legacy. The 

14recommended language to use is jexl, which is newer and most powerful. 

15 

16# The input sections are marked with 'TODO' 

17 

18# #### Steps to complete: 

19# 1. Setting up the expression language jexl 

20# 2. Applying the expression language to device attributes 

21# 3. Testing the expression language via MQTT messages 

22# 4. Applying the expression language to device attributes in a multi-entity scenario 

23""" 

24 

25# Import packages 

26import time 

27import datetime 

28 

29from filip.clients.ngsi_v2 import IoTAClient, ContextBrokerClient 

30from filip.models.base import FiwareHeader 

31from filip.models.ngsi_v2.context import ContextEntity, NamedContextAttribute 

32from filip.models.ngsi_v2.iot import ( 

33 Device, 

34 ServiceGroup, 

35 TransportProtocol, 

36 PayloadProtocol, 

37 DeviceAttribute, 

38 ExpressionLanguage, 

39) 

40from filip.utils.cleanup import clear_all 

41from paho.mqtt import client as mqtt_client 

42from paho.mqtt.client import CallbackAPIVersion 

43 

44# Host address of Context Broker 

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

46 

47# Host address of IoT-Agent 

48IOTA_URL = "http://localhost:4041" 

49 

50# MQTT Broker 

51MQTT_BROKER_HOST = "localhost" 

52MQTT_BROKER_PORT = 1883 

53 

54# FIWARE Service 

55SERVICE = "filip_tutorial" 

56SERVICE_PATH = "/" 

57 

58# ToDo: Change the APIKEY to something unique. This represent the "token" 

59# for IoT devices to connect (send/receive data ) with the platform. In the 

60# context of MQTT, APIKEY is linked with the topic used for communication. 

61APIKEY = "your_apikey" 

62 

63if __name__ == "__main__": 

64 # FIWARE Header 

65 fiware_header = FiwareHeader(service=SERVICE, service_path=SERVICE_PATH) 

66 

67 # Cleanup at the beginning 

68 clear_all(fiware_header=fiware_header, cb_url=CB_URL, iota_url=IOTA_URL) 

69 

70 # IoT Agent and OCB Client 

71 iota_client = IoTAClient(url=IOTA_URL, fiware_header=fiware_header) 

72 cb_client = ContextBrokerClient(url=CB_URL, fiware_header=fiware_header) 

73 

74 # TODO: Setting expression language to JEXL at Service Group level 

75 service_group1 = ServiceGroup( 

76 entity_type="Thing", 

77 resource="/iot/json", 

78 apikey=APIKEY, 

79 expressionLanguage=ExpressionLanguage.JEXL, 

80 ) 

81 iota_client.post_group(service_group=service_group1) 

82 

83 # TODO: Create a device with two attributes 'location' and 'fillingLevel' that use 

84 # expressions. These attributes are based on the attributes 'longitude', 

85 # 'latitude' and 'level', while: 

86 # 1. 'location' is an array with 'longitude' and 'latitude'. 

87 # 2. 'fillingLevel' is 'level' divided by 100 

88 device1 = Device( 

89 device_id="waste_container_001", 

90 entity_name="urn:ngsi-ld:WasteContainer:001", 

91 entity_type="WasteContainer", 

92 transport=TransportProtocol.MQTT, 

93 protocol=PayloadProtocol.IOTA_JSON, 

94 attributes=[ 

95 DeviceAttribute(name="latitude", type="Number"), 

96 DeviceAttribute(name="longitude", type="Number"), 

97 DeviceAttribute(name="level", type="Number"), 

98 DeviceAttribute( 

99 name="location", type="Array", expression="[longitude, latitude]" 

100 ), 

101 DeviceAttribute( 

102 name="fillingLevel", type="Number", expression="level / 100" 

103 ), 

104 ], 

105 ) 

106 iota_client.post_device(device=device1) 

107 

108 # TODO: Setting expression language to JEXL at Device level with five attributes, while 

109 # 1. The attribute 'value' (Number) is itself multiplied by 5. The attribute 

110 # 2. 'consumption' (Text) is the trimmed version of the attribute 'spaces' (Text). 

111 # 3. The attribute 'iso_time' (Text) is the current 'timestamp' (Number) transformed into the ISO format. 

112 device2 = Device( 

113 device_id="waste_container_002", 

114 entity_name="urn:ngsi-ld:WasteContainer:002", 

115 entity_type="WasteContainer", 

116 transport=TransportProtocol.MQTT, 

117 protocol=PayloadProtocol.IOTA_JSON, 

118 expressionLanguage=ExpressionLanguage.JEXL, 

119 attributes=[ 

120 DeviceAttribute(name="value", type="Number", expression="5 * value"), 

121 DeviceAttribute(name="spaces", type="Text"), 

122 DeviceAttribute(name="consumption", type="Text", expression="spaces|trim"), 

123 DeviceAttribute(name="timestamp", type="Number"), 

124 DeviceAttribute( 

125 name="iso_time", type="Text", expression="timestamp|toisodate" 

126 ), 

127 ], 

128 ) 

129 iota_client.post_device(device=device2) 

130 

131 client = mqtt_client.Client(callback_api_version=CallbackAPIVersion.VERSION2) 

132 client.username_pw_set(username="", password="") 

133 client.connect(MQTT_BROKER_HOST, MQTT_BROKER_PORT) 

134 client.loop_start() 

135 

136 # TODO: Publish attributes 'level', 'longitude' and 'latitude' of device1 

137 client.publish( 

138 topic=f"/json/{APIKEY}/{device1.device_id}/attrs", 

139 payload='{"level": 99, "longitude": 12.0, "latitude": 23.0}', 

140 ) 

141 

142 # TODO: Publish attributes 'value', 'spaces' and 'timestamp' (in ms) of device2 

143 client.publish( 

144 topic=f"/json/{APIKEY}/{device2.device_id}/attrs", 

145 payload=f'{{ "value": 10, "spaces": " foobar ",' 

146 f' "timestamp": {datetime.datetime.now().timestamp() * 1000} }}', 

147 ) 

148 

149 client.disconnect() 

150 

151 time.sleep(2) 

152 

153 # Printing context entities of OCB 

154 for context_entity in cb_client.get_entity_list(entity_types=["WasteContainer"]): 

155 print(context_entity.model_dump_json(indent=4)) 

156 

157 # Creating two SubWeatherStation entities 

158 entity1 = ContextEntity( 

159 id="urn:ngsi-ld:SubWeatherStation:001", type="SubWeatherStation" 

160 ) 

161 entity1.add_attributes(attrs=[NamedContextAttribute(name="vol", type="Number")]) 

162 cb_client.post_entity(entity1) 

163 

164 entity2 = ContextEntity( 

165 id="urn:ngsi-ld:SubWeatherStation:002", type="SubWeatherStation" 

166 ) 

167 entity2.add_attributes(attrs=[NamedContextAttribute(name="vol", type="Number")]) 

168 cb_client.post_entity(entity2) 

169 

170 # TODO: Create a weather station device with multi entity attributes (Number). 

171 # 'v' is multiplied by 100 and is a standard attribute. 

172 # 'v1' and 'v2' are multiplied by 100 and should be linked with entities of 

173 # the SubWeatherStation. 

174 # The name of each attribute is 'vol'. 

175 device3 = Device( 

176 device_id="weather_station_001", 

177 entity_name="urn:ngsi-ld:WeatherStation:001", 

178 entity_type="WeatherStation", 

179 transport=TransportProtocol.MQTT, 

180 protocol=PayloadProtocol.IOTA_JSON, 

181 expressionLanguage=ExpressionLanguage.JEXL, 

182 attributes=[ 

183 DeviceAttribute( 

184 object_id="v1", 

185 name="vol", 

186 type="Number", 

187 expression="100 * v1", 

188 entity_name="urn:ngsi-ld:SubWeatherStation:001", 

189 entity_type="SubWeatherStation", 

190 ), 

191 DeviceAttribute( 

192 object_id="v2", 

193 name="vol", 

194 type="Number", 

195 expression="100 * v2", 

196 entity_name="urn:ngsi-ld:SubWeatherStation:002", 

197 entity_type="SubWeatherStation", 

198 ), 

199 DeviceAttribute( 

200 object_id="v", name="vol", type="Number", expression="100 * v" 

201 ), 

202 ], 

203 ) 

204 iota_client.post_device(device=device3) 

205 

206 client = mqtt_client.Client(callback_api_version=CallbackAPIVersion.VERSION2) 

207 client.username_pw_set(username="", password="") 

208 client.connect(MQTT_BROKER_HOST, MQTT_BROKER_PORT) 

209 client.loop_start() 

210 

211 # TODO: Publish values to all attributes of device3 

212 client.publish( 

213 topic=f"/json/{APIKEY}/{device3.device_id}/attrs", 

214 payload='{"v1": 10, "v2": 20, "v": 30}', 

215 ) 

216 

217 client.disconnect() 

218 

219 time.sleep(2) 

220 

221 # Printing context entities of OCB 

222 for context_entity in cb_client.get_entity_list( 

223 entity_types=["WeatherStation", "SubWeatherStation"] 

224 ): 

225 print(context_entity.model_dump_json(indent=4))