211 |
211 |
212 |
212 |
213 |
213 |
214 |
214 |
215 |
215 |
216 def _SetSavedConfiguration(WebNode_id, newConfig): |
216 def _SetModbusSavedConfiguration(WebNode_id, newConfig): |
217 """ Stores a dictionary in a persistant file containing the Modbus parameter configuration """ |
217 """ Stores a dictionary in a persistant file containing the Modbus parameter configuration """ |
218 WebNode_entry = _WebNodeList[WebNode_id] |
218 WebNode_entry = _WebNodeList[WebNode_id] |
219 |
219 |
220 if WebNode_entry["DefaultConfiguration"] == newConfig: |
220 if WebNode_entry["DefaultConfiguration"] == newConfig: |
221 |
221 |
222 _DelSavedConfiguration(WebNode_id) |
222 _DelModbusSavedConfiguration(WebNode_id) |
223 WebNode_entry["SavedConfiguration"] = None |
223 WebNode_entry["ModbusSavedConfiguration"] = None |
224 |
224 |
225 else: |
225 else: |
226 |
226 |
227 # Add the addr_type and node_type to the data that will be saved to file |
227 # Add the addr_type and node_type to the data that will be saved to file |
228 # This allows us to confirm the saved data contains the correct addr_type |
228 # This allows us to confirm the saved data contains the correct addr_type |
235 filename = WebNode_entry["filename"] |
235 filename = WebNode_entry["filename"] |
236 |
236 |
237 with open(os.path.realpath(filename), 'w') as f: |
237 with open(os.path.realpath(filename), 'w') as f: |
238 json.dump(save_info, f, sort_keys=True, indent=4) |
238 json.dump(save_info, f, sort_keys=True, indent=4) |
239 |
239 |
240 WebNode_entry["SavedConfiguration"] = newConfig |
240 WebNode_entry["ModbusSavedConfiguration"] = newConfig |
241 |
241 |
242 |
242 |
243 |
243 |
244 |
244 |
245 def _DelSavedConfiguration(WebNode_id): |
245 def _DelModbusSavedConfiguration(WebNode_id): |
246 """ Deletes the file cotaining the persistent Modbus configuration """ |
246 """ Deletes the file cotaining the persistent Modbus configuration """ |
247 filename = _WebNodeList[WebNode_id]["filename"] |
247 filename = _WebNodeList[WebNode_id]["filename"] |
248 |
248 |
249 if os.path.exists(filename): |
249 if os.path.exists(filename): |
250 os.remove(filename) |
250 os.remove(filename) |
251 |
251 |
252 |
252 |
253 |
253 |
254 |
254 |
255 def _GetSavedConfiguration(WebNode_id): |
255 def _GetModbusSavedConfiguration(WebNode_id): |
256 """ |
256 """ |
257 Returns a dictionary containing the Modbus parameter configuration |
257 Returns a dictionary containing the Modbus parameter configuration |
258 that was last saved to file. If no file exists, or file contains |
258 that was last saved to file. If no file exists, or file contains |
259 wrong addr_type (i.e. 'tcp', 'rtu' or 'ascii' -> does not match the |
259 wrong addr_type (i.e. 'tcp', 'rtu' or 'ascii' -> does not match the |
260 addr_type of the WebNode_id), then return None |
260 addr_type of the WebNode_id), then return None |
301 |
301 |
302 return current_config |
302 return current_config |
303 |
303 |
304 |
304 |
305 |
305 |
306 def _SetPLCConfiguration(WebNode_id, newconfig): |
306 def _SetModbusPLCConfiguration(WebNode_id, newconfig): |
307 """ |
307 """ |
308 Stores the Modbus parameter configuration into the |
308 Stores the Modbus parameter configuration into the |
309 the C variables in the loaded PLC (.so file) |
309 the C variables in the loaded PLC (.so file) |
310 """ |
310 """ |
311 C_node_id = _WebNodeList[WebNode_id]["C_node_id"] |
311 C_node_id = _WebNodeList[WebNode_id]["C_node_id"] |
317 SetParamFuncs[par_name](C_node_id, value) |
317 SetParamFuncs[par_name](C_node_id, value) |
318 |
318 |
319 |
319 |
320 |
320 |
321 |
321 |
322 def _GetWebviewConfigurationValue(ctx, WebNode_id, argument): |
322 def _GetModbusWebviewConfigurationValue(ctx, WebNode_id, argument): |
323 """ |
323 """ |
324 Callback function, called by the web interface (NevowServer.py) |
324 Callback function, called by the web interface (NevowServer.py) |
325 to fill in the default value of each parameter of the web form |
325 to fill in the default value of each parameter of the web form |
326 |
326 |
327 Note that the real callback function is a dynamically created function that |
327 Note that the real callback function is a dynamically created function that |
333 except Exception: |
333 except Exception: |
334 return "" |
334 return "" |
335 |
335 |
336 |
336 |
337 |
337 |
338 def OnButtonSave(**kwargs): |
338 def OnModbusButtonSave(**kwargs): |
339 """ |
339 """ |
340 Function called when user clicks 'Save' button in web interface |
340 Function called when user clicks 'Save' button in web interface |
341 The function will configure the Modbus plugin in the PLC with the values |
341 The function will configure the Modbus plugin in the PLC with the values |
342 specified in the web interface. However, values must be validated first! |
342 specified in the web interface. However, values must be validated first! |
343 |
343 |
344 Note that this function does not get called directly. The real callback |
344 Note that this function does not get called directly. The real callback |
345 function is the dynamic __OnButtonSave() function, which will add the |
345 function is the dynamic __OnButtonSave() function, which will add the |
346 "WebNode_id" argument, and call this function to do the work. |
346 "WebNode_id" argument, and call this function to do the work. |
347 """ |
347 """ |
348 |
348 |
349 #PLCObject.LogMessage("Modbus web server extension::OnButtonSave() Called") |
349 #PLCObject.LogMessage("Modbus web server extension::OnModbusButtonSave() Called") |
350 |
350 |
351 newConfig = {} |
351 newConfig = {} |
352 WebNode_id = kwargs.get("WebNode_id", None) |
352 WebNode_id = kwargs.get("WebNode_id", None) |
353 WebParamList = _WebNodeList[WebNode_id]["WebParamList"] |
353 WebParamList = _WebNodeList[WebNode_id]["WebParamList"] |
354 |
354 |
364 # return |
364 # return |
365 |
365 |
366 # store to file the new configuration so that |
366 # store to file the new configuration so that |
367 # we can recoup the configuration the next time the PLC |
367 # we can recoup the configuration the next time the PLC |
368 # has a cold start (i.e. when Beremiz_service.py is retarted) |
368 # has a cold start (i.e. when Beremiz_service.py is retarted) |
369 _SetSavedConfiguration(WebNode_id, newConfig) |
369 _SetModbusSavedConfiguration(WebNode_id, newConfig) |
370 |
370 |
371 # Configure PLC with the current Modbus parameters |
371 # Configure PLC with the current Modbus parameters |
372 _SetPLCConfiguration(WebNode_id, newConfig) |
372 _SetModbusPLCConfiguration(WebNode_id, newConfig) |
373 |
373 |
374 # Update the viewable configuration |
374 # Update the viewable configuration |
375 # The PLC may have coerced the values on calling _SetPLCConfiguration() |
375 # The PLC may have coerced the values on calling _SetModbusPLCConfiguration() |
376 # so we do not set it directly to newConfig |
376 # so we do not set it directly to newConfig |
377 _WebNodeList[WebNode_id]["WebviewConfiguration"] = _GetPLCConfiguration(WebNode_id) |
377 _WebNodeList[WebNode_id]["WebviewConfiguration"] = _GetModbusPLCConfiguration(WebNode_id) |
378 |
378 |
379 |
379 |
380 |
380 |
381 def OnButtonReset(**kwargs): |
381 def OnModbusButtonReset(**kwargs): |
382 """ |
382 """ |
383 Function called when user clicks 'Delete' button in web interface |
383 Function called when user clicks 'Delete' button in web interface |
384 The function will delete the file containing the persistent |
384 The function will delete the file containing the persistent |
385 Modbus configution |
385 Modbus configution |
386 """ |
386 """ |
387 |
387 |
388 WebNode_id = kwargs.get("WebNode_id", None) |
388 WebNode_id = kwargs.get("WebNode_id", None) |
389 |
389 |
390 # Delete the file |
390 # Delete the file |
391 _DelSavedConfiguration(WebNode_id) |
391 _DelModbusSavedConfiguration(WebNode_id) |
392 |
392 |
393 # Set the current configuration to the default (hardcoded in C) |
393 # Set the current configuration to the default (hardcoded in C) |
394 new_config = _WebNodeList[WebNode_id]["DefaultConfiguration"] |
394 new_config = _WebNodeList[WebNode_id]["DefaultConfiguration"] |
395 _SetPLCConfiguration(WebNode_id, new_config) |
395 _SetModbusPLCConfiguration(WebNode_id, new_config) |
396 |
396 |
397 #Update the webviewconfiguration |
397 #Update the webviewconfiguration |
398 _WebNodeList[WebNode_id]["WebviewConfiguration"] = new_config |
398 _WebNodeList[WebNode_id]["WebviewConfiguration"] = new_config |
399 |
399 |
400 # Reset SavedConfiguration |
400 # Reset ModbusSavedConfiguration |
401 _WebNodeList[WebNode_id]["SavedConfiguration"] = None |
401 _WebNodeList[WebNode_id]["ModbusSavedConfiguration"] = None |
402 |
402 |
403 |
403 |
404 |
404 |
405 |
405 |
406 |
406 |
459 WebNode_entry["WebviewConfiguration"] = None |
459 WebNode_entry["WebviewConfiguration"] = None |
460 |
460 |
461 # Upon PLC load, this Dictionary is initialised with the Modbus configuration |
461 # Upon PLC load, this Dictionary is initialised with the Modbus configuration |
462 # hardcoded in the C file |
462 # hardcoded in the C file |
463 # (i.e. the configuration inserted in Beremiz IDE when project was compiled) |
463 # (i.e. the configuration inserted in Beremiz IDE when project was compiled) |
464 WebNode_entry["DefaultConfiguration"] = _GetPLCConfiguration(WebNode_id) |
464 WebNode_entry["DefaultConfiguration"] = _GetModbusPLCConfiguration(WebNode_id) |
465 WebNode_entry["WebviewConfiguration"] = WebNode_entry["DefaultConfiguration"] |
465 WebNode_entry["WebviewConfiguration"] = WebNode_entry["DefaultConfiguration"] |
466 |
466 |
467 # Dictionary that stores the Modbus configuration currently stored in a file |
467 # Dictionary that stores the Modbus configuration currently stored in a file |
468 # Currently only used to decide whether or not to show the "Delete" button on the |
468 # Currently only used to decide whether or not to show the "Delete" button on the |
469 # web interface (only shown if "SavedConfiguration" is not None) |
469 # web interface (only shown if "ModbusSavedConfiguration" is not None) |
470 SavedConfig = _GetSavedConfiguration(WebNode_id) |
470 SavedConfig = _GetModbusSavedConfiguration(WebNode_id) |
471 WebNode_entry["SavedConfiguration"] = SavedConfig |
471 WebNode_entry["ModbusSavedConfiguration"] = SavedConfig |
472 |
472 |
473 if SavedConfig is not None: |
473 if SavedConfig is not None: |
474 _SetPLCConfiguration(WebNode_id, SavedConfig) |
474 _SetModbusPLCConfiguration(WebNode_id, SavedConfig) |
475 WebNode_entry["WebviewConfiguration"] = SavedConfig |
475 WebNode_entry["WebviewConfiguration"] = SavedConfig |
476 |
476 |
477 # Define the format for the web form used to show/change the current parameters |
477 # Define the format for the web form used to show/change the current parameters |
478 # We first declare a dynamic function to work as callback to obtain the default values for each parameter |
478 # We first declare a dynamic function to work as callback to obtain the default values for each parameter |
479 # Note: We transform every parameter into a string |
479 # Note: We transform every parameter into a string |
484 # However, the annotate.Choice parameters (and all parameters that derive from it, |
484 # However, the annotate.Choice parameters (and all parameters that derive from it, |
485 # sucn as Parity, Baud, etc.) require the default value as a string |
485 # sucn as Parity, Baud, etc.) require the default value as a string |
486 # even though we store it as an integer, which is the data type expected |
486 # even though we store it as an integer, which is the data type expected |
487 # by the set_***() C functions in mb_runtime.c |
487 # by the set_***() C functions in mb_runtime.c |
488 def __GetWebviewConfigurationValue(ctx, argument): |
488 def __GetWebviewConfigurationValue(ctx, argument): |
489 return str(_GetWebviewConfigurationValue(ctx, WebNode_id, argument)) |
489 return str(_GetModbusWebviewConfigurationValue(ctx, WebNode_id, argument)) |
490 |
490 |
491 webFormInterface = [(name, web_dtype (label=web_label, default=__GetWebviewConfigurationValue)) |
491 webFormInterface = [(name, web_dtype (label=web_label, default=__GetWebviewConfigurationValue)) |
492 for name, web_label, c_dtype, web_dtype in WebNode_entry["WebParamList"]] |
492 for name, web_label, c_dtype, web_dtype in WebNode_entry["WebParamList"]] |
493 |
493 |
494 # Configure the web interface to include the Modbus config parameters |
494 # Configure the web interface to include the Modbus config parameters |
495 def __OnButtonSave(**kwargs): |
495 def __OnButtonSave(**kwargs): |
496 OnButtonSave(WebNode_id=WebNode_id, **kwargs) |
496 OnModbusButtonSave(WebNode_id=WebNode_id, **kwargs) |
497 |
497 |
498 WebSettings = NS.newExtensionSetting("Modbus #"+ str(WebNode_id), config_hash) |
498 WebSettings = NS.newExtensionSetting("Modbus #"+ str(WebNode_id), config_hash) |
499 |
499 |
500 WebSettings.addSettings( |
500 WebSettings.addSettings( |
501 "ModbusConfigParm" + config_hash, # name (internal, may not contain spaces, ...) |
501 "ModbusConfigParm" + config_hash, # name (internal, may not contain spaces, ...) |
503 webFormInterface, # fields |
503 webFormInterface, # fields |
504 _("Apply"), # button label |
504 _("Apply"), # button label |
505 __OnButtonSave) # callback |
505 __OnButtonSave) # callback |
506 |
506 |
507 def __OnButtonReset(**kwargs): |
507 def __OnButtonReset(**kwargs): |
508 return OnButtonReset(WebNode_id = WebNode_id, **kwargs) |
508 return OnModbusButtonReset(WebNode_id = WebNode_id, **kwargs) |
509 |
509 |
510 def getConfigStatus(): |
510 def getModbusConfigStatus(): |
511 if WebNode_entry["WebviewConfiguration"] == WebNode_entry["DefaultConfiguration"]: |
511 if WebNode_entry["WebviewConfiguration"] == WebNode_entry["DefaultConfiguration"]: |
512 return "Unchanged" |
512 return "Unchanged" |
513 return "Modified" |
513 return "Modified" |
514 |
514 |
515 WebSettings.addSettings( |
515 WebSettings.addSettings( |
516 "ModbusConfigDelSaved" + config_hash, # name (internal, may not contain spaces, ...) |
516 "ModbusConfigDelSaved" + config_hash, # name (internal, may not contain spaces, ...) |
517 _("Modbus Configuration: ") + config_name, # description (user visible label) |
517 _("Modbus Configuration: ") + config_name, # description (user visible label) |
518 [ ("status", |
518 [ ("status", |
519 annotate.String(label=_("Current state"), |
519 annotate.String(label=_("Current state"), |
520 immutable=True, |
520 immutable=True, |
521 default=lambda *k:getConfigStatus())), |
521 default=lambda *k:getModbusConfigStatus())), |
522 ], # fields (empty, no parameters required!) |
522 ], # fields (empty, no parameters required!) |
523 _("Reset"), # button label |
523 _("Reset"), # button label |
524 __OnButtonReset) |
524 __OnButtonReset) |
525 |
525 |
526 |
526 |