diff --git a/Classes/WebServer/WebServer.py b/Classes/WebServer/WebServer.py index 1f931fb61..eaf3d4efd 100644 --- a/Classes/WebServer/WebServer.py +++ b/Classes/WebServer/WebServer.py @@ -31,8 +31,7 @@ domoticz_error_api, domoticz_log_api, domoticz_status_api) -from Modules.matomo_request import (matomo_opt_in_action, - matomo_opt_out_action) +from Modules.matomo_request import matomo_opt_in_action, matomo_opt_out_action from Modules.sendZigateCommand import sendZigateCmd from Modules.tools import get_device_nickname, is_hex from Modules.txPower import set_TxPower @@ -86,6 +85,7 @@ class WebServer(object): from Classes.WebServer.rest_CfgReporting import ( rest_cfgrpt_ondemand, rest_cfgrpt_ondemand_with_config) from Classes.WebServer.rest_change_ModelName import rest_change_model_name + from Classes.WebServer.rest_device_params import rest_device_param from Classes.WebServer.rest_Device_Settings_Help import \ rest_device_settings_help from Classes.WebServer.rest_Energy import (rest_req_nwk_full, diff --git a/Classes/WebServer/dispatcher.py b/Classes/WebServer/dispatcher.py index 0fe69bb3a..c90a2f4b9 100644 --- a/Classes/WebServer/dispatcher.py +++ b/Classes/WebServer/dispatcher.py @@ -19,146 +19,148 @@ def setup_list_rest_commands( self ): - + list_rest_commands = [ - ( {"Name": "battery-state", "Verbs": {"GET"}, "function": self.rest_battery_state} ), - ( {"Name": "bind-lst-cluster", "Verbs": {"GET"}, "function": self.rest_bindLSTcluster} ), - ( {"Name": "bind-lst-device", "Verbs": {"GET"}, "function": self.rest_bindLSTdevice} ), - ( {"Name": "binding", "Verbs": {"PUT"}, "function": self.rest_binding} ), - ( {"Name": "binding-table-req", "Verbs": {"GET"}, "function": self.rest_binding_table_req} ), - ( {"Name": "binding-table-disp", "Verbs": {"GET"}, "function": self.rest_binding_table_disp} ), - ( {"Name": "binding-group", "Verbs": {"PUT"}, "function": self.rest_group_binding} ), - ( {"Name": "casaia-list-devices", "Verbs": {"GET"}, "function": self.rest_casa_device_list } ), - ( {"Name": "casaia-update-ircode", "Verbs": {"PUT"}, "function": self.rest_casa_device_ircode_update } ), - ( {"Name": "cfgrpt-ondemand", "Verbs": {"GET"}, "function": self.rest_cfgrpt_ondemand} ), - ( {"Name": "cfgrpt-ondemand-config", "Verbs": { "GET", "PUT", "DELETE" }, "function": self.rest_cfgrpt_ondemand_with_config} ), - ( {"Name": "change-channel", "Verbs": {"PUT"}, "function": self.rest_change_channel} ), - ( {"Name": "change-model", "Verbs": {"PUT"}, "function": self.rest_change_model_name} ), - ( {"Name": "clear-error-history", "Verbs": {"GET"}, "function": self.rest_logErrorHistoryClear } ), - ( {"Name": "dev-cap", "Verbs": {"GET"}, "function": self.rest_dev_capabilities} ), - ( {"Name": "dev-command", "Verbs": {"PUT"}, "function": self.rest_dev_command} ), - ( {"Name": "device", "Verbs": {"GET"}, "function": self.rest_Device} ), - ( {"Name": "device-settings-help", "Verbs": {"GET"}, "function": self.rest_device_settings_help} ), - ( {"Name": "domoticz-env", "Verbs": {"GET"}, "function": self.rest_domoticz_env} ), - ( {"Name": "help", "Verbs": {"GET"}, "function": None} ), - ( {"Name": "full-reprovisionning", "Verbs": {"PUT"}, "function": self.rest_full_reprovisionning} ), - ( {"Name": "log-error-history", "Verbs": {"GET"}, "function": self.rest_logErrorHistory} ), - ( {"Name": "new-hrdwr", "Verbs": {"GET"}, "function": self.rest_new_hrdwr} ), - ( {"Name": "nwk-stat", "Verbs": {"GET", "DELETE"}, "function": self.rest_nwk_stat} ), - ( {"Name": "non-optmize-device-configuration", "Verbs": {"GET"}, "function": self.non_optmize_device_configuration} ), - ( {"Name": "ota-firmware-device-list", "Verbs": {"GET"}, "function": self.rest_ota_devices_for_manufcode } ), - ( {"Name": "ota-firmware-list", "Verbs": {"GET"}, "function": self.rest_ota_firmware_list} ), - ( {"Name": "ota-firmware-update", "Verbs": {"PUT"}, "function": self.rest_ota_firmware_update } ), - ( {"Name": "permit-to-join", "Verbs": {"GET", "PUT"}, "function": self.rest_PermitToJoin} ), - ( {"Name": "plugin-ping", "Verbs": {"GET"}, "function": self.rest_plugin_ping} ), - ( {"Name": "plugin-health", "Verbs": {"GET"}, "function": self.rest_plugin_health} ), - ( {"Name": "plugin-log", "Verbs": {"GET"}, "function": self.rest_logPlugin} ), - ( {"Name": "plugin-upgrade", "Verbs": {"GET"}, "function": self.rest_plugin_upgrade} ), - ( {"Name": "plugin-restart", "Verbs": {"GET"}, "function": self.rest_plugin_restart} ), - ( {"Name": "plugin-stat", "Verbs": {"GET"}, "function": self.rest_plugin_stat} ), - ( {"Name": "plugin", "Verbs": {"GET"}, "function": self.rest_PluginEnv} ), - ( {"Name": "raw-command", "Verbs": {"PUT"}, "function": self.rest_raw_command} ), - ( {"Name": "raw-zigbee", "Verbs": {"PUT"}, "function": self.rest_raw_zigbee} ), - ( {"Name": "rcv-nw-hrdwr", "Verbs": {"GET"}, "function": self.rest_rcv_nw_hrdwr} ), - ( {"Name": "recreate-widgets", "Verbs": {"PUT"}, "function": self.rest_recreate_widgets} ), - ( {"Name": "reload-device-conf", "Verbs": {"GET"}, "function": self.rest_reload_device_conf} ), - ( {"Name": "req-nwk-full", "Verbs": {"GET"}, "function": self.rest_req_nwk_full} ), - ( {"Name": "req-nwk-inter", "Verbs": {"GET"}, "function": self.rest_req_nwk_inter} ), - ( {"Name": "req-topologie", "Verbs": {"GET"}, "function": self.rest_req_topologie} ), - ( {"Name": "rescan-groups", "Verbs": {"GET"}, "function": self.rest_rescan_group} ), - ( {"Name": "restart-needed", "Verbs": {"GET"}, "function": self.rest_restart_needed} ), - ( {"Name": "scan-device-for-grp", "Verbs": {"PUT"}, "function": self.rest_scan_devices_for_group } ), - ( {"Name": "setting-debug", "Verbs": {"GET", "PUT"}, "function": self.rest_Settings_with_debug} ), - ( {"Name": "setting", "Verbs": {"GET", "PUT"}, "function": self.rest_Settings_wo_debug} ), - ( {"Name": "sw-reset-zigate", "Verbs": {"GET"}, "function": self.rest_reset_zigate} ), - ( {"Name": "sw-reset-coordinator", "Verbs": {"GET"}, "function": self.rest_reset_zigate} ), - ( {"Name": "topologie", "Verbs": {"GET", "DELETE"}, "function": self.rest_netTopologie} ), - ( {"Name": "unbinding", "Verbs": {"PUT"}, "function": self.rest_unbinding} ), - ( {"Name": "unbinding-group", "Verbs": {"PUT"}, "function": self.rest_group_unbinding} ), - ( {"Name": "upgrade-certified-devices", "Verbs": {"GET"}, "function": self.rest_certified_devices_update} ), - ( {"Name": "zdevice-name", "Verbs": {"GET", "PUT", "DELETE"}, "function": self.rest_zDevice_name} ), - ( {"Name": "zdevice-raw", "Verbs": {"GET", "PUT"}, "function": self.rest_zDevice_raw} ), - ( {"Name": "zdevice", "Verbs": {"GET", "DELETE"}, "function": self.rest_zDevice} ), - ( {"Name": "zgroup-list-available-device", "Verbs": {"GET"}, "function": self.rest_zGroup_lst_avlble_dev } ), - ( {"Name": "zgroup", "Verbs": {"GET", "PUT"}, "function": self.rest_zGroup} ), - ( {"Name": "zigate-erase-PDM", "Verbs": {"GET"}, "function": self.rest_zigate_erase_PDM} ), - ( {"Name": "zigate-mode", "Verbs": {"GET"}, "function": self.rest_zigate_mode} ), - ( {"Name": "zigate", "Verbs": {"GET"}, "function": self.rest_zigate } ), - ( {"Name": "zlinky", "Verbs": {"GET"}, "function": self.rest_zlinky } ), - ( {"Name": "coordinator-erase-PDM", "Verbs": {"GET"}, "function": self.rest_zigate_erase_PDM} ), - ( {"Name": "coordinator-mode", "Verbs": {"GET"}, "function": self.rest_zigate_mode} ), - ( {"Name": "coordinator", "Verbs": {"GET"}, "function": self.rest_zigate} ), + {"Name": "battery-state", "Verbs": {"GET"}, "function": self.rest_battery_state}, + {"Name": "bind-lst-cluster", "Verbs": {"GET"}, "function": self.rest_bindLSTcluster}, + {"Name": "bind-lst-device", "Verbs": {"GET"}, "function": self.rest_bindLSTdevice}, + {"Name": "binding", "Verbs": {"PUT"}, "function": self.rest_binding}, + {"Name": "binding-table-req", "Verbs": {"GET"}, "function": self.rest_binding_table_req}, + {"Name": "binding-table-disp", "Verbs": {"GET"}, "function": self.rest_binding_table_disp}, + {"Name": "binding-group", "Verbs": {"PUT"}, "function": self.rest_group_binding}, + {"Name": "casaia-list-devices", "Verbs": {"GET"}, "function": self.rest_casa_device_list }, + {"Name": "casaia-update-ircode", "Verbs": {"PUT"}, "function": self.rest_casa_device_ircode_update }, + {"Name": "cfgrpt-ondemand", "Verbs": {"GET"}, "function": self.rest_cfgrpt_ondemand}, + {"Name": "cfgrpt-ondemand-config", "Verbs": { "GET", "PUT", "DELETE" }, "function": self.rest_cfgrpt_ondemand_with_config}, + {"Name": "change-channel", "Verbs": {"PUT"}, "function": self.rest_change_channel}, + {"Name": "change-model", "Verbs": {"PUT"}, "function": self.rest_change_model_name}, + {"Name": "clear-error-history", "Verbs": {"GET"}, "function": self.rest_logErrorHistoryClear }, + {"Name": "dev-cap", "Verbs": {"GET"}, "function": self.rest_dev_capabilities}, + {"Name": "dev-command", "Verbs": {"PUT"}, "function": self.rest_dev_command}, + {"Name": "device", "Verbs": {"GET"}, "function": self.rest_Device}, + {"Name": "device-param", "Verbs": {"GET", "PUT"}, "function": self.rest_device_param}, + {"Name": "device-settings-help", "Verbs": {"GET"}, "function": self.rest_device_settings_help}, + {"Name": "domoticz-env", "Verbs": {"GET"}, "function": self.rest_domoticz_env}, + {"Name": "help", "Verbs": {"GET"}, "function": None}, + {"Name": "full-reprovisionning", "Verbs": {"PUT"}, "function": self.rest_full_reprovisionning}, + {"Name": "log-error-history", "Verbs": {"GET"}, "function": self.rest_logErrorHistory}, + {"Name": "new-hrdwr", "Verbs": {"GET"}, "function": self.rest_new_hrdwr}, + {"Name": "nwk-stat", "Verbs": {"GET", "DELETE"}, "function": self.rest_nwk_stat}, + {"Name": "non-optmize-device-configuration", "Verbs": {"GET"}, "function": self.non_optmize_device_configuration}, + {"Name": "ota-firmware-device-list", "Verbs": {"GET"}, "function": self.rest_ota_devices_for_manufcode }, + {"Name": "ota-firmware-list", "Verbs": {"GET"}, "function": self.rest_ota_firmware_list}, + {"Name": "ota-firmware-update", "Verbs": {"PUT"}, "function": self.rest_ota_firmware_update }, + {"Name": "permit-to-join", "Verbs": {"GET", "PUT"}, "function": self.rest_PermitToJoin}, + {"Name": "plugin-ping", "Verbs": {"GET"}, "function": self.rest_plugin_ping}, + {"Name": "plugin-health", "Verbs": {"GET"}, "function": self.rest_plugin_health}, + {"Name": "plugin-log", "Verbs": {"GET"}, "function": self.rest_logPlugin}, + {"Name": "plugin-upgrade", "Verbs": {"GET"}, "function": self.rest_plugin_upgrade}, + {"Name": "plugin-restart", "Verbs": {"GET"}, "function": self.rest_plugin_restart}, + {"Name": "plugin-stat", "Verbs": {"GET"}, "function": self.rest_plugin_stat}, + {"Name": "plugin", "Verbs": {"GET"}, "function": self.rest_PluginEnv}, + {"Name": "raw-command", "Verbs": {"PUT"}, "function": self.rest_raw_command}, + {"Name": "raw-zigbee", "Verbs": {"PUT"}, "function": self.rest_raw_zigbee}, + {"Name": "rcv-nw-hrdwr", "Verbs": {"GET"}, "function": self.rest_rcv_nw_hrdwr}, + {"Name": "recreate-widgets", "Verbs": {"PUT"}, "function": self.rest_recreate_widgets}, + {"Name": "reload-device-conf", "Verbs": {"GET"}, "function": self.rest_reload_device_conf}, + {"Name": "req-nwk-full", "Verbs": {"GET"}, "function": self.rest_req_nwk_full}, + {"Name": "req-nwk-inter", "Verbs": {"GET"}, "function": self.rest_req_nwk_inter}, + {"Name": "req-topologie", "Verbs": {"GET"}, "function": self.rest_req_topologie}, + {"Name": "rescan-groups", "Verbs": {"GET"}, "function": self.rest_rescan_group}, + {"Name": "restart-needed", "Verbs": {"GET"}, "function": self.rest_restart_needed}, + {"Name": "scan-device-for-grp", "Verbs": {"PUT"}, "function": self.rest_scan_devices_for_group }, + {"Name": "setting-debug", "Verbs": {"GET", "PUT"}, "function": self.rest_Settings_with_debug}, + {"Name": "setting", "Verbs": {"GET", "PUT"}, "function": self.rest_Settings_wo_debug}, + {"Name": "sw-reset-zigate", "Verbs": {"GET"}, "function": self.rest_reset_zigate}, + {"Name": "sw-reset-coordinator", "Verbs": {"GET"}, "function": self.rest_reset_zigate}, + {"Name": "topologie", "Verbs": {"GET", "DELETE"}, "function": self.rest_netTopologie}, + {"Name": "unbinding", "Verbs": {"PUT"}, "function": self.rest_unbinding}, + {"Name": "unbinding-group", "Verbs": {"PUT"}, "function": self.rest_group_unbinding}, + {"Name": "upgrade-certified-devices", "Verbs": {"GET"}, "function": self.rest_certified_devices_update}, + {"Name": "zdevice-name", "Verbs": {"GET", "PUT", "DELETE"}, "function": self.rest_zDevice_name}, + {"Name": "zdevice-raw", "Verbs": {"GET", "PUT"}, "function": self.rest_zDevice_raw}, + {"Name": "zdevice", "Verbs": {"GET", "DELETE"}, "function": self.rest_zDevice}, + {"Name": "zgroup-list-available-device", "Verbs": {"GET"}, "function": self.rest_zGroup_lst_avlble_dev }, + {"Name": "zgroup", "Verbs": {"GET", "PUT"}, "function": self.rest_zGroup}, + {"Name": "zigate-erase-PDM", "Verbs": {"GET"}, "function": self.rest_zigate_erase_PDM}, + {"Name": "zigate-mode", "Verbs": {"GET"}, "function": self.rest_zigate_mode}, + {"Name": "zigate", "Verbs": {"GET"}, "function": self.rest_zigate }, + {"Name": "zlinky", "Verbs": {"GET"}, "function": self.rest_zlinky }, + {"Name": "coordinator-erase-PDM", "Verbs": {"GET"}, "function": self.rest_zigate_erase_PDM}, + {"Name": "coordinator-mode", "Verbs": {"GET"}, "function": self.rest_zigate_mode}, + {"Name": "coordinator", "Verbs": {"GET"}, "function": self.rest_zigate}, ] - - for command in list_rest_commands: - _name = command["Name"] - _verbs = command["Verbs"] - _function = command["function"] - if _name in REST_COMMANDS: - self.logging("Error", "setup_list_rest_commands - %s already loaded" %_name) - REST_COMMANDS[ _name ] = { "Name": _name, "Verbs": _verbs, "function": _function} + + for rest_command in list_rest_commands: + name = rest_command["Name"] + if name in REST_COMMANDS: + self.logging("Error", f"setup_list_rest_commands - {name} already loaded") + else: + REST_COMMANDS[name] = { + "Name": name, + "Verbs": rest_command["Verbs"], + "function": rest_command["function"] + } + def do_rest(self, Connection, verb, data, version, command, parameters): - - self.logging("Debug", "do_rest - Verb: %s, Command: %s, Param: %s" % (verb, command, parameters)) + self.logging("Debug", f"do_rest - Verb: {verb}, Command: {command}, Param: {parameters}") - HTTPresponse = {} + HTTPresponse = None if command in REST_COMMANDS and verb in REST_COMMANDS[command]["Verbs"]: - self.logging("Debug", "do_rest - Verb: %s, Command: %s, Param: %s found ready to execute" % (verb, command, parameters)) + self.logging("Debug", f"do_rest - Verb: {verb}, Command: {command}, Param: {parameters} found, ready to execute") HTTPresponse = execute_rest_command(self, verb, data, version, command, parameters) - else: - self.logging("Error", "do_rest - Verb: %s, Command: %s, Param: %s not found !" % (verb, command, parameters)) + self.logging("Error", f"do_rest - Verb: {verb}, Command: {command}, Param: {parameters} not found!") - self.logging("Debug", "==> return HTTPresponse: %s" % (HTTPresponse)) - if HTTPresponse == {} or HTTPresponse is None: - # We reach here due to failure ! + # Handle missing or invalid response + if not HTTPresponse: + self.logging("Debug", "do_rest - No valid HTTPresponse, preparing error message") HTTPresponse = prepare_error_message(self, command) - self.logging("Debug", "==> sending HTTPresponse: %s to %s" % (HTTPresponse, Connection)) + self.logging("Debug", f"==> sending HTTPresponse: {HTTPresponse} to {Connection}") self.sendResponse(Connection, HTTPresponse) def execute_rest_command(self, verb, data, version, command, parameters): response = setupHeadersResponse() - if self.pluginconf.pluginConf["enableKeepalive"]: - response["Headers"]["Connection"] = "Keep-alive" - else: - response["Headers"]["Connection"] = "Close" - response["Headers"]["Cache-Control"] = "no-cache, no-store, must-revalidate" - response["Headers"]["Pragma"] = "no-cache" - response["Headers"]["Expires"] = "0" - response["Headers"]["Accept"] = "*/*" - + connection_status = "Keep-alive" if self.pluginconf.pluginConf["enableKeepalive"] else "Close" + response["Headers"].update({ + "Connection": connection_status, + "Cache-Control": "no-cache, no-store, must-revalidate", + "Pragma": "no-cache", + "Expires": "0", + "Accept": "*/*", + }) + if command == "help": - response = prepare_help_response(self) + return prepare_help_response(self) - elif version == "1" and REST_COMMANDS[command]["function"]: - self.logging("Debug", "do_rest - calling REST_COMMANDS[%s]['function'] with %s %s %s" % (command, verb, data, parameters)) - response = REST_COMMANDS[command]["function"](verb, data, parameters) + if version == "1" and (func := REST_COMMANDS[command].get("function")): + self.logging("Debug", f"do_rest - calling REST_COMMANDS[{command}]['function'] with {verb}, {data}, {parameters}") + return func(verb, data, parameters) - elif version == "2" and REST_COMMANDS[command]["functionv2"]: - response = REST_COMMANDS[command]["functionv2"](verb, data, parameters) + if version == "2" and (func_v2 := REST_COMMANDS[command].get("functionv2")): + return func_v2(verb, data, parameters) return response def prepare_help_response(self): response = prepResponseMessage(self, setupHeadersResponse()) - _data = {} - for x in REST_COMMANDS: - _data[x] = {"Verbs": []} - for y in REST_COMMANDS[x]["Verbs"]: - _data[x]["Verbs"].append(y) - response["Data"] = json.dumps(_data) + response["Data"] = json.dumps({ + x: {"Verbs": REST_COMMANDS[x]["Verbs"]} for x in REST_COMMANDS + }) return response - + def prepare_error_message(self, command): response = prepResponseMessage(self, setupHeadersResponse()) - response["Status"] = "400 BAD REQUEST" - response["Data"] = "Unknown REST command: %s" % command + response.update({ + "Status": "400 BAD REQUEST", + "Data": f"Unknown REST command: {command}", + }) response["Headers"]["Content-Type"] = "text/plain; charset=utf-8" return response diff --git a/Classes/WebServer/rest_device_params.py b/Classes/WebServer/rest_device_params.py new file mode 100644 index 000000000..2e4d659a0 --- /dev/null +++ b/Classes/WebServer/rest_device_params.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Implementation of Zigbee for Domoticz plugin. +# +# This file is part of Zigbee for Domoticz plugin. https://github.com/zigbeefordomoticz/Domoticz-Zigbee +# (C) 2015-2024 +# +# Initial authors: zaraki673 & pipiche38 +# +# SPDX-License-Identifier: GPL-3.0 license + +import json +from time import time + +from Classes.WebServer.headerResponse import (prepResponseMessage, + setupHeadersResponse) +from Modules.paramDevice import sanity_check_of_param + + +def rest_device_param(self, verb, data, parameters): + + self.logging("Log", "rest_update_device_param -->Verb: %s Data: %s Parameters: %s" % (verb, data, parameters)) + if verb == "GET": + return rest_get_device_param(self, parameters) + + elif verb == "PUT": + return rest_update_device_param(self, data) + + return prepResponseMessage(self, setupHeadersResponse()) + + +def rest_get_device_param( self, parameters): + + _response = prepResponseMessage(self, setupHeadersResponse()) + + if len(parameters) != 1: + return _log_and_return_with_error(self, "rest_get_device_param - unexpected parameter: %s", parameters, "unexpected parameter %s ", _response, ) + + nwkid = parameters[0] + if len(nwkid) == 16: + # We are assuming that is an ieee instead of nwkid + nwkid = self.IEEE2NWK.get( nwkid ) + + if nwkid not in self.ListOfDevices: + return _log_and_return_with_error(self, "rest_get_device_param - Unknown device %s ", nwkid, "unknown device %s ", _response, ) + device_info = self.ListOfDevices.get( nwkid ) + device_param = device_info.get("Param", "{}") + + _response["Data"] = json.dumps(device_param, sort_keys=False) + return _response + + +def rest_update_device_param(self, data): + + # curl -X PUT -d '{ + # "Param": {'Disabled': 0, 'resetMotiondelay': 0, 'ConfigurationReportChunk': 3, 'ReadAttributeChunk': 4}, + # "NWKID": "1234" + # }' http://127.0.0.1:9441/rest-z4d/1/device-param + + _response = prepResponseMessage(self, setupHeadersResponse()) + + data = data.decode("utf8") + data = eval(data) + self.logging( "Log", "rest_update_device_param - Data: %s" % data) + + parameter = data.get("Param") + nwkid = data.get("NWKID") + ieee = data.get("IEEE") + + if nwkid is None and ieee is None: + return _log_and_return_with_error(self, "rest_update_device_param - missing IEEE or NWKID", "unexpected parameter %s ", _response, ) + + if ieee: + nwkid = self.IEEE2NWK.get( ieee ) + + if parameter is None or nwkid is None: + return _log_and_return_with_error(self, "rest_update_device_param - unexpected parameter: %s", data, "unexpected parameter %s ", _response, ) + if nwkid not in self.ListOfDevices: + return _log_and_return_with_error(self, "rest_update_device_param - Unknown device %s ", nwkid, "unknown device %s ", _response, ) + old_parameter = self.ListOfDevices[ nwkid ].get("Param") + _response["Data"] = {"NwkId %s set Param from: %s to %s" % (nwkid, old_parameter, parameter)} + + self.ListOfDevices[ nwkid ]["Param"] = parameter + + sanity_check_of_param(self, nwkid) + + return _response + + +def _log_and_return_with_error(self, arg0, arg1, arg2, _response): + self.logging("Error", arg0 % arg1) + _response["Data"] = {arg2 % arg1} + return _response