32 |
32 |
33 |
33 |
34 # Will contain references to the C functions |
34 # Will contain references to the C functions |
35 # (implemented in beremiz/bacnet/runtime/server.c) |
35 # (implemented in beremiz/bacnet/runtime/server.c) |
36 # used to get/set the BACnet specific configuration paramters |
36 # used to get/set the BACnet specific configuration paramters |
37 GetParamFuncs = {} |
37 BacnetGetParamFuncs = {} |
38 SetParamFuncs = {} |
38 BacnetSetParamFuncs = {} |
39 |
39 |
40 |
40 |
41 # Upon PLC load, this Dictionary is initialised with the BACnet configuration |
41 # Upon PLC load, this Dictionary is initialised with the BACnet configuration |
42 # hardcoded in the C file |
42 # hardcoded in the C file |
43 # (i.e. the configuration inserted in Beremiz IDE when project was compiled) |
43 # (i.e. the configuration inserted in Beremiz IDE when project was compiled) |
44 _DefaultConfiguration = None |
44 _BacnetDefaultConfiguration = None |
45 |
45 |
46 |
46 |
47 # Dictionary that contains the BACnet configuration currently being shown |
47 # Dictionary that contains the BACnet configuration currently being shown |
48 # on the web interface |
48 # on the web interface |
49 # This configuration will almost always be identical to the current |
49 # This configuration will almost always be identical to the current |
50 # configuration in the PLC (i.e., the current state stored in the |
50 # configuration in the PLC (i.e., the current state stored in the |
51 # C variables in the .so file). |
51 # C variables in the .so file). |
52 # The configuration viewed on the web will only be different to the current |
52 # The configuration viewed on the web will only be different to the current |
53 # configuration when the user edits the configuration, and when |
53 # configuration when the user edits the configuration, and when |
54 # the user asks to save the edited configuration but it contains an error. |
54 # the user asks to save the edited configuration but it contains an error. |
55 _WebviewConfiguration = None |
55 _BacnetWebviewConfiguration = None |
56 |
56 |
57 |
57 |
58 # Dictionary that stores the BACnet configuration currently stored in a file |
58 # Dictionary that stores the BACnet configuration currently stored in a file |
59 # Currently only used to decide whether or not to show the "Delete" button on the |
59 # Currently only used to decide whether or not to show the "Delete" button on the |
60 # web interface (only shown if _SavedConfiguration is not None) |
60 # web interface (only shown if _BacnetSavedConfiguration is not None) |
61 _SavedConfiguration = None |
61 _BacnetSavedConfiguration = None |
62 |
62 |
63 |
63 |
64 # File to which the new BACnet configuration gets stored on the PLC |
64 # File to which the new BACnet configuration gets stored on the PLC |
65 # Note that the stored configuration is likely different to the |
65 # Note that the stored configuration is likely different to the |
66 # configuration hardcoded in C generated code (.so file), so |
66 # configuration hardcoded in C generated code (.so file), so |
162 |
162 |
163 |
163 |
164 |
164 |
165 |
165 |
166 |
166 |
167 def _SetSavedConfiguration(BACnetConfig): |
167 def _SetBacnetSavedConfiguration(BACnetConfig): |
168 """ Stores in a file a dictionary containing the BACnet parameter configuration """ |
168 """ Stores in a file a dictionary containing the BACnet parameter configuration """ |
169 global _SavedConfiguration |
169 global _BacnetSavedConfiguration |
170 |
170 |
171 if BACnetConfig == _DefaultConfiguration : |
171 if BACnetConfig == _BacnetDefaultConfiguration : |
172 _DelSavedConfiguration() |
172 _DelBacnetSavedConfiguration() |
173 _SavedConfiguration = None |
173 _BacnetSavedConfiguration = None |
174 else : |
174 else : |
175 with open(os.path.realpath(_BACnetConfFilename), 'w') as f: |
175 with open(os.path.realpath(_BACnetConfFilename), 'w') as f: |
176 json.dump(BACnetConfig, f, sort_keys=True, indent=4) |
176 json.dump(BACnetConfig, f, sort_keys=True, indent=4) |
177 _SavedConfiguration = BACnetConfig |
177 _BacnetSavedConfiguration = BACnetConfig |
178 |
178 |
179 |
179 |
180 def _DelSavedConfiguration(): |
180 def _DelBacnetSavedConfiguration(): |
181 """ Deletes the file cotaining the persistent BACnet configuration """ |
181 """ Deletes the file cotaining the persistent BACnet configuration """ |
182 if os.path.exists(_BACnetConfFilename): |
182 if os.path.exists(_BACnetConfFilename): |
183 os.remove(_BACnetConfFilename) |
183 os.remove(_BACnetConfFilename) |
184 |
184 |
185 |
185 |
186 def _GetSavedConfiguration(): |
186 def _GetBacnetSavedConfiguration(): |
187 """ |
187 """ |
188 # Returns a dictionary containing the BACnet parameter configuration |
188 # Returns a dictionary containing the BACnet parameter configuration |
189 # that was last saved to file. If no file exists, then return None |
189 # that was last saved to file. If no file exists, then return None |
190 """ |
190 """ |
191 try: |
191 try: |
192 #if os.path.isfile(_BACnetConfFilename): |
192 #if os.path.isfile(_BACnetConfFilename): |
193 saved_config = json.load(open(_BACnetConfFilename)) |
193 saved_config = json.load(open(_BACnetConfFilename)) |
194 except Exception: |
194 except Exception: |
195 return None |
195 return None |
196 |
196 |
197 if _CheckConfiguration(saved_config): |
197 if _CheckBacnetConfiguration(saved_config): |
198 return saved_config |
198 return saved_config |
199 else: |
199 else: |
200 return None |
200 return None |
201 |
201 |
202 |
202 |
203 def _GetPLCConfiguration(): |
203 def _GetBacnetPLCConfiguration(): |
204 """ |
204 """ |
205 # Returns a dictionary containing the current BACnet parameter configuration |
205 # Returns a dictionary containing the current BACnet parameter configuration |
206 # stored in the C variables in the loaded PLC (.so file) |
206 # stored in the C variables in the loaded PLC (.so file) |
207 """ |
207 """ |
208 current_config = {} |
208 current_config = {} |
209 for par_name, x1, x2, x3 in BACnet_parameters: |
209 for par_name, x1, x2, x3 in BACnet_parameters: |
210 value = GetParamFuncs[par_name]() |
210 value = BacnetGetParamFuncs[par_name]() |
211 if value is not None: |
211 if value is not None: |
212 current_config[par_name] = value |
212 current_config[par_name] = value |
213 |
213 |
214 return current_config |
214 return current_config |
215 |
215 |
216 |
216 |
217 def _SetPLCConfiguration(BACnetConfig): |
217 def _SetBacnetPLCConfiguration(BACnetConfig): |
218 """ |
218 """ |
219 # Stores the BACnet parameter configuration into the |
219 # Stores the BACnet parameter configuration into the |
220 # the C variables in the loaded PLC (.so file) |
220 # the C variables in the loaded PLC (.so file) |
221 """ |
221 """ |
222 for par_name in BACnetConfig: |
222 for par_name in BACnetConfig: |
223 value = BACnetConfig[par_name] |
223 value = BACnetConfig[par_name] |
224 #PLCObject.LogMessage("BACnet web server extension::_SetPLCConfiguration() Setting " |
224 #PLCObject.LogMessage("BACnet web server extension::_SetBacnetPLCConfiguration() Setting " |
225 # + par_name + " to " + str(value) ) |
225 # + par_name + " to " + str(value) ) |
226 if value is not None: |
226 if value is not None: |
227 SetParamFuncs[par_name](value) |
227 BacnetSetParamFuncs[par_name](value) |
228 # update the configuration shown on the web interface |
228 # update the configuration shown on the web interface |
229 global _WebviewConfiguration |
229 global _BacnetWebviewConfiguration |
230 _WebviewConfiguration = _GetPLCConfiguration() |
230 _BacnetWebviewConfiguration = _GetBacnetPLCConfiguration() |
231 |
231 |
232 |
232 |
233 |
233 |
234 def _GetWebviewConfigurationValue(ctx, argument): |
234 def _GetBacnetWebviewConfigurationValue(ctx, argument): |
235 """ |
235 """ |
236 # Callback function, called by the web interface (NevowServer.py) |
236 # Callback function, called by the web interface (NevowServer.py) |
237 # to fill in the default value of each parameter |
237 # to fill in the default value of each parameter |
238 """ |
238 """ |
239 try: |
239 try: |
240 return _WebviewConfiguration[argument.name] |
240 return _BacnetWebviewConfiguration[argument.name] |
241 except Exception: |
241 except Exception: |
242 return "" |
242 return "" |
243 |
243 |
244 |
244 |
245 # The configuration of the web form used to see/edit the BACnet parameters |
245 # The configuration of the web form used to see/edit the BACnet parameters |
246 webFormInterface = [(name, web_dtype (label=web_label, default=_GetWebviewConfigurationValue)) |
246 webFormInterface = [(name, web_dtype (label=web_label, default=_GetBacnetWebviewConfigurationValue)) |
247 for name, web_label, c_dtype, web_dtype in BACnet_parameters] |
247 for name, web_label, c_dtype, web_dtype in BACnet_parameters] |
248 |
248 |
249 |
249 |
250 def OnButtonSave(**kwargs): |
250 def OnBacnetButtonSave(**kwargs): |
251 """ |
251 """ |
252 # Function called when user clicks 'Save' button in web interface |
252 # Function called when user clicks 'Save' button in web interface |
253 # The function will configure the BACnet plugin in the PLC with the values |
253 # The function will configure the BACnet plugin in the PLC with the values |
254 # specified in the web interface. However, values must be validated first! |
254 # specified in the web interface. However, values must be validated first! |
255 """ |
255 """ |
256 |
256 |
257 #PLCObject.LogMessage("BACnet web server extension::OnButtonSave() Called") |
257 #PLCObject.LogMessage("BACnet web server extension::OnBacnetButtonSave() Called") |
258 |
258 |
259 newConfig = {} |
259 newConfig = {} |
260 for par_name, x1, x2, x3 in BACnet_parameters: |
260 for par_name, x1, x2, x3 in BACnet_parameters: |
261 value = kwargs.get(par_name, None) |
261 value = kwargs.get(par_name, None) |
262 if value is not None: |
262 if value is not None: |
263 newConfig[par_name] = value |
263 newConfig[par_name] = value |
264 |
264 |
265 |
265 |
266 # First check if configuration is OK. |
266 # First check if configuration is OK. |
267 if not _CheckWebConfiguration(newConfig): |
267 if not _CheckBacnetWebConfiguration(newConfig): |
268 return |
268 return |
269 |
269 |
270 # store to file the new configuration so that |
270 # store to file the new configuration so that |
271 # we can recoup the configuration the next time the PLC |
271 # we can recoup the configuration the next time the PLC |
272 # has a cold start (i.e. when Beremiz_service.py is retarted) |
272 # has a cold start (i.e. when Beremiz_service.py is retarted) |
273 _SetSavedConfiguration(newConfig) |
273 _SetBacnetSavedConfiguration(newConfig) |
274 |
274 |
275 # Configure PLC with the current BACnet parameters |
275 # Configure PLC with the current BACnet parameters |
276 _SetPLCConfiguration(newConfig) |
276 _SetBacnetPLCConfiguration(newConfig) |
277 |
277 |
278 |
278 |
279 |
279 |
280 def OnButtonReset(**kwargs): |
280 def OnBacnetButtonReset(**kwargs): |
281 """ |
281 """ |
282 # Function called when user clicks 'Delete' button in web interface |
282 # Function called when user clicks 'Delete' button in web interface |
283 # The function will delete the file containing the persistent |
283 # The function will delete the file containing the persistent |
284 # BACnet configution |
284 # BACnet configution |
285 """ |
285 """ |
286 |
286 |
287 # Delete the file |
287 # Delete the file |
288 _DelSavedConfiguration() |
288 _DelBacnetSavedConfiguration() |
289 # Set the current configuration to the default (hardcoded in C) |
289 # Set the current configuration to the default (hardcoded in C) |
290 _SetPLCConfiguration(_DefaultConfiguration) |
290 _SetBacnetPLCConfiguration(_BacnetDefaultConfiguration) |
291 # Reset global variable |
291 # Reset global variable |
292 global _SavedConfiguration |
292 global _BacnetSavedConfiguration |
293 _SavedConfiguration = None |
293 _BacnetSavedConfiguration = None |
294 |
294 |
295 |
295 |
296 |
296 |
297 # location_str is replaced by extension's value in CTNGenerateC call |
297 # location_str is replaced by extension's value in CTNGenerateC call |
298 def _runtime_bacnet_websettings_%(location_str)s_init(): |
298 def _runtime_bacnet_websettings_%(location_str)s_init(): |
315 GetParamFuncName = "__bacnet_%(location_str)s_get_ConfigParam_" + name |
315 GetParamFuncName = "__bacnet_%(location_str)s_get_ConfigParam_" + name |
316 SetParamFuncName = "__bacnet_%(location_str)s_set_ConfigParam_" + name |
316 SetParamFuncName = "__bacnet_%(location_str)s_set_ConfigParam_" + name |
317 |
317 |
318 # XXX TODO : stop reading from PLC .so file. This code is template code |
318 # XXX TODO : stop reading from PLC .so file. This code is template code |
319 # that can use modbus extension build data |
319 # that can use modbus extension build data |
320 GetParamFuncs[name] = getattr(PLCObject.PLClibraryHandle, GetParamFuncName) |
320 BacnetGetParamFuncs[name] = getattr(PLCObject.PLClibraryHandle, GetParamFuncName) |
321 GetParamFuncs[name].restype = c_dtype |
321 BacnetGetParamFuncs[name].restype = c_dtype |
322 GetParamFuncs[name].argtypes = None |
322 BacnetGetParamFuncs[name].argtypes = None |
323 |
323 |
324 SetParamFuncs[name] = getattr(PLCObject.PLClibraryHandle, SetParamFuncName) |
324 BacnetSetParamFuncs[name] = getattr(PLCObject.PLClibraryHandle, SetParamFuncName) |
325 SetParamFuncs[name].restype = None |
325 BacnetSetParamFuncs[name].restype = None |
326 SetParamFuncs[name].argtypes = [c_dtype] |
326 BacnetSetParamFuncs[name].argtypes = [c_dtype] |
327 |
327 |
328 # Default configuration is the configuration done in Beremiz IDE |
328 # Default configuration is the configuration done in Beremiz IDE |
329 # whose parameters get hardcoded into C, and compiled into the .so file |
329 # whose parameters get hardcoded into C, and compiled into the .so file |
330 # We read the default configuration from the .so file before the values |
330 # We read the default configuration from the .so file before the values |
331 # get changed by the user using the web server, or by the call (further on) |
331 # get changed by the user using the web server, or by the call (further on) |
332 # to _SetPLCConfiguration(SavedConfiguration) |
332 # to _SetBacnetPLCConfiguration(BacnetSavedConfiguration) |
333 global _DefaultConfiguration |
333 global _BacnetDefaultConfiguration |
334 _DefaultConfiguration = _GetPLCConfiguration() |
334 _BacnetDefaultConfiguration = _GetBacnetPLCConfiguration() |
335 |
335 |
336 # Show the current PLC configuration on the web interface |
336 # Show the current PLC configuration on the web interface |
337 global _WebviewConfiguration |
337 global _BacnetWebviewConfiguration |
338 _WebviewConfiguration = _GetPLCConfiguration() |
338 _BacnetWebviewConfiguration = _GetBacnetPLCConfiguration() |
339 |
339 |
340 # Read from file the last used configuration, which is likely |
340 # Read from file the last used configuration, which is likely |
341 # different to the hardcoded configuration. |
341 # different to the hardcoded configuration. |
342 # We Reset the current configuration (i.e., the config stored in the |
342 # We Reset the current configuration (i.e., the config stored in the |
343 # variables of .so file) to this saved configuration |
343 # variables of .so file) to this saved configuration |
344 # so the PLC will start off with this saved configuration instead |
344 # so the PLC will start off with this saved configuration instead |
345 # of the hardcoded (in Beremiz C generated code) configuration values. |
345 # of the hardcoded (in Beremiz C generated code) configuration values. |
346 # |
346 # |
347 # Note that _SetPLCConfiguration() will also update |
347 # Note that _SetBacnetPLCConfiguration() will also update |
348 # _WebviewConfiguration , if necessary. |
348 # _BacnetWebviewConfiguration , if necessary. |
349 global _SavedConfiguration |
349 global _BacnetSavedConfiguration |
350 _SavedConfiguration = _GetSavedConfiguration() |
350 _BacnetSavedConfiguration = _GetBacnetSavedConfiguration() |
351 if _SavedConfiguration is not None: |
351 if _BacnetSavedConfiguration is not None: |
352 if _CheckConfiguration(_SavedConfiguration): |
352 if _CheckBacnetConfiguration(_BacnetSavedConfiguration): |
353 _SetPLCConfiguration(_SavedConfiguration) |
353 _SetBacnetPLCConfiguration(_BacnetSavedConfiguration) |
354 |
354 |
355 WebSettings = NS.newExtensionSetting("BACnet extension", "bacnet_token") |
355 WebSettings = NS.newExtensionSetting("BACnet extension", "bacnet_token") |
356 |
356 |
357 # Configure the web interface to include the BACnet config parameters |
357 # Configure the web interface to include the BACnet config parameters |
358 WebSettings.addSettings( |
358 WebSettings.addSettings( |
359 "BACnetConfigParm", # name |
359 "BACnetConfigParm", # name |
360 _("BACnet Configuration"), # description |
360 _("BACnet Configuration"), # description |
361 webFormInterface, # fields |
361 webFormInterface, # fields |
362 _("Apply"), # button label |
362 _("Apply"), # button label |
363 OnButtonSave) # callback |
363 OnBacnetButtonSave) # callback |
364 |
364 |
365 # Add the Delete button to the web interface |
365 # Add the Delete button to the web interface |
366 WebSettings.addSettings( |
366 WebSettings.addSettings( |
367 "BACnetConfigDelSaved", # name |
367 "BACnetConfigDelSaved", # name |
368 _("BACnet Configuration"), # description |
368 _("BACnet Configuration"), # description |
369 [ ("status", |
369 [ ("status", |
370 annotate.String(label=_("Current state"), |
370 annotate.String(label=_("Current state"), |
371 immutable=True, |
371 immutable=True, |
372 default=lambda *k:getConfigStatus())), |
372 default=lambda *k:getBacnetConfigStatus())), |
373 ], # fields (empty, no parameters required!) |
373 ], # fields (empty, no parameters required!) |
374 _("Reset"), # button label |
374 _("Reset"), # button label |
375 OnButtonReset) |
375 OnBacnetButtonReset) |
376 |
376 |
377 |
377 |
378 |
378 |
379 def getConfigStatus(): |
379 def getBacnetConfigStatus(): |
380 if _WebviewConfiguration == _DefaultConfiguration : |
380 if _BacnetWebviewConfiguration == _BacnetDefaultConfiguration : |
381 return "Unchanged" |
381 return "Unchanged" |
382 return "Modified" |
382 return "Modified" |
383 |
383 |
384 |
384 |
385 # location_str is replaced by extension's value in CTNGenerateC call |
385 # location_str is replaced by extension's value in CTNGenerateC call |