diff --git a/Classes/WebServer/WebServer.py b/Classes/WebServer/WebServer.py index eaf3d4efd..efe6fcd2a 100644 --- a/Classes/WebServer/WebServer.py +++ b/Classes/WebServer/WebServer.py @@ -1082,8 +1082,8 @@ def rest_zDevice(self, verb, data, parameters): if attribut == "Battery" and attribut in self.ListOfDevices[item]: if self.ListOfDevices[item]["Battery"] in ( {}, ) and "IASBattery" in self.ListOfDevices[item]: device[attribut] = str(self.ListOfDevices[item][ "IASBattery" ]) - elif isinstance( self.ListOfDevices[item]["Battery"], int): - device[attribut] = self.ListOfDevices[item]["Battery"] + elif isinstance( self.ListOfDevices[item]["Battery"], (int,float)): + device[attribut] = int(self.ListOfDevices[item]["Battery"]) device["BatteryInside"] = True elif item == "CheckParam": @@ -1530,43 +1530,53 @@ def rest_zigate_mode(self, verb, data, parameters): _response["Data"] = json.dumps("ZiGate mode: %s requested" % mode) return _response + def rest_battery_state(self, verb, data, parameters): _response = prepResponseMessage(self, setupHeadersResponse()) _response["Headers"]["Content-Type"] = "application/json; charset=utf-8" if verb == "GET": _battEnv = {"Battery":{"<30%":{}, "<50%": {}, ">50%" : {}},"Update Time":{ "Unknown": {}, "< 1 week": {}, "> 1 week": {}}} for x in self.ListOfDevices: + self.logging("Debug", f"rest_battery_state - {x}") if x == "0000": - continue + continue - if self.ListOfDevices[x]["ZDeviceName"] == "": - _deviceName = x - else: - _deviceName = self.ListOfDevices[x]["ZDeviceName"] + battery = self.ListOfDevices[x].get("Battery") - if "Battery" in self.ListOfDevices[x] and isinstance(self.ListOfDevices[x]["Battery"], int): - if self.ListOfDevices[x]["Battery"] > 50: - _battEnv["Battery"][">50%"][_deviceName] = {"Battery": self.ListOfDevices[x]["Battery"]} + if battery is None: + continue + self.logging("Debug", f"rest_battery_state - {x} Battery found") - elif self.ListOfDevices[x]["Battery"] > 30: - _battEnv["Battery"]["<50%"][_deviceName] = {"Battery": self.ListOfDevices[x]["Battery"]} + _deviceName = self.ListOfDevices[x].get("ZDeviceName", x ) - else: - _battEnv["Battery"]["<30%"][_deviceName] = {"Battery": self.ListOfDevices[x]["Battery"]} + if not isinstance( battery, (int, float)): + self.logging("Debug", f"rest_battery_state - {x} Battery found, but not int !! {type(battery)}") + continue + battery = int(battery) - if "BatteryUpdateTime" in self.ListOfDevices[x]: - if (int(time.time()) - self.ListOfDevices[x]["BatteryUpdateTime"]) > 604800: # one week in seconds - _battEnv["Update Time"]["> 1 week"][_deviceName] = {"BatteryUpdateTime": self.ListOfDevices[x]["BatteryUpdateTime"]} + if self.ListOfDevices[x]["Battery"] > 50: + _battEnv["Battery"][">50%"][_deviceName] = {"Battery": battery} - else: - _battEnv["Update Time"]["< 1 week"][_deviceName] = {"BatteryUpdateTime": self.ListOfDevices[x]["BatteryUpdateTime"]} + elif self.ListOfDevices[x]["Battery"] > 30: + _battEnv["Battery"]["<50%"][_deviceName] = {"Battery": battery} + + else: + _battEnv["Battery"]["<30%"][_deviceName] = {"Battery": battery} + + if "BatteryUpdateTime" in self.ListOfDevices[x]: + if (int(time.time()) - self.ListOfDevices[x]["BatteryUpdateTime"]) > 604800: # one week in seconds + _battEnv["Update Time"]["> 1 week"][_deviceName] = {"BatteryUpdateTime": self.ListOfDevices[x]["BatteryUpdateTime"]} else: - _battEnv["Update Time"]["Unknown"][_deviceName] = "Unknown" + _battEnv["Update Time"]["< 1 week"][_deviceName] = {"BatteryUpdateTime": self.ListOfDevices[x]["BatteryUpdateTime"]} + else: + _battEnv["Update Time"]["Unknown"][_deviceName] = "Unknown" + + self.logging("Debug", f"rest_battery_state - {_battEnv}") _response["Data"] = json.dumps(_battEnv, sort_keys=True) return _response - + def logging(self, logType, message): self.log.logging("WebServer", logType, message) diff --git a/Modules/actuators.py b/Modules/actuators.py index 4fd182545..2e8621d85 100644 --- a/Modules/actuators.py +++ b/Modules/actuators.py @@ -257,7 +257,7 @@ def actuator_setcolor(self, nwkid, EPout, value, Color): if ( "Param" in self.ListOfDevices[nwkid] and "moveToLevel" in self.ListOfDevices[nwkid]["Param"] ): transitionMoveLevel = "%04x" % int(self.ListOfDevices[nwkid]["Param"]["moveToLevel"]) - force_color_command = get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "FORCE_COLOR_COMMAND", return_default=None) + force_color_command = is_tuya_hue_saturation_needed(self, nwkid) ColorCapabilitiesList = device_color_capabilities( self, nwkid, EPout) self.log.logging("Command", "Debug", "actuator_setcolor force_color_command %s" % force_color_command, nwkid) @@ -266,7 +266,7 @@ def actuator_setcolor(self, nwkid, EPout, value, Color): handle_color_mode_2(self, nwkid, EPout, Hue_List) actuator_setlevel(self, nwkid, EPout, value, "Light", transitionMoveLevel) - elif Hue_List["m"] == 3 and force_color_command == "TuyaMovetoHueandSaturation": + elif Hue_List["m"] == 3 and force_color_command: handle_color_mode_tuya( self, nwkid, EPout, Hue_List, value) elif Hue_List["m"] == 3: @@ -308,7 +308,7 @@ def handle_color_mode_3(self, nwkid, EPout, Hue_List): #strxy = Hex_Format(4, x) + Hex_Format(4, y) self.log.logging("Command", "Debug", "handle_color_mode_3 Set Temp X: %s Y: %s" % (x, y), nwkid) transitionMoveLevel , transitionRGB , transitionMoveLevel , transitionHue , transitionTemp = get_all_transition_mode( self, nwkid) - if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None): + if is_tuya_rgb_mode_needed(self, nwkid): tuya_color_control_rgbMode( self, nwkid, "01") zcl_move_to_colour(self, nwkid, EPout, Hex_Format(4, x), Hex_Format(4, y), transitionRGB) @@ -326,7 +326,7 @@ def handle_color_mode_4(self, nwkid, EPout, Hue_List ): TempMired = 1000000 // TempKelvin self.log.logging( "Command", "Log", "handle_color_mode_4 Set Temp Kelvin: %s-%s" % ( TempMired, Hex_Format(4, TempMired)), nwkid ) - if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None): + if is_tuya_rgb_mode_needed(self, nwkid): tuya_color_control_rgbMode( self, nwkid, "01") zcl_move_to_colour_temperature( self, nwkid, EPout, Hex_Format(4, TempMired), transitionTemp) @@ -339,7 +339,7 @@ def handle_color_mode_4(self, nwkid, EPout, Hue_List ): self.log.logging("Command", "Log", "handle_color_mode_4 Set Hue X: %s Saturation: %s" % ( hue, saturation), nwkid) - if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None): + if is_tuya_rgb_mode_needed(self, nwkid): tuya_color_control_rgbMode( self, nwkid, "01") zcl_move_hue_and_saturation(self, nwkid, EPout, Hex_Format(2, hue), Hex_Format(2, saturation), transitionRGB) @@ -353,10 +353,10 @@ def handle_color_mode_9998( self, nwkid, EPout, Hue_List, value): hue = int(hue * 254 // 360) self.log.logging("Command", "Debug", "handle_color_mode_9998 Set Hue X: %s Saturation: %s" % (hue, saturation), nwkid) - if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None): + if is_tuya_rgb_mode_needed(self, nwkid): tuya_color_control_rgbMode( self, nwkid, "01") - if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "FORCE_COLOR_COMMAND", return_default=None) == "TuyaMovetoHueandSaturation": + if is_tuya_hue_saturation_needed(self, nwkid): tuya_Move_To_Hue_Saturation( self, nwkid, hue, saturation, value) else: zcl_move_hue_and_saturation(self, nwkid, EPout, Hex_Format(2, hue), Hex_Format(2, saturation), transitionRGB) @@ -365,6 +365,22 @@ def handle_color_mode_9998( self, nwkid, EPout, Hue_List, value): actuator_setlevel(self, nwkid, EPout, value, "Light", transitionMoveLevel) +def is_tuya_hue_saturation_needed(self, nwkid): + model = self.ListOfDevices[nwkid].get("Model","") + tuya_move_to_hue_and_saturation = get_deviceconf_parameter_value(self, model, "FORCE_COLOR_COMMAND", return_default=None) or get_device_config_param(self, nwkid, "FORCE_COLOR_COMMAND") + return tuya_move_to_hue_and_saturation == "TuyaMovetoHueandSaturation" + + +def is_tuya_rgb_mode_needed(self, nwkid): + model = self.ListOfDevices[nwkid].get("Model","") + return get_deviceconf_parameter_value( + self, + model, + "TUYAColorControlRgbMode", + return_default=None, + ) or get_device_config_param(self, nwkid, "TUYAColorControlRgbMode") + + def handle_color_mode_tuya( self, nwkid, EPout, Hue_List, value): self.log.logging("Command", "Debug", "handle_color_mode_tuya Hue_list: %s Value: %s" % ( @@ -379,7 +395,7 @@ def handle_color_mode_tuya( self, nwkid, EPout, Hue_List, value): self.log.logging("Command", "Log", "handle_color_mode_tuya Set Hue X: %s Saturation: %s Value: %s" % ( hue, saturation, value), nwkid) - if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None): + if is_tuya_rgb_mode_needed(self, nwkid): tuya_color_control_rgbMode( self, nwkid, "01") tuya_Move_To_Hue_Saturation( self, nwkid, EPout, hue, saturation, transitionHue, value ) diff --git a/Modules/checkingUpdate.py b/Modules/checkingUpdate.py index d67c305f8..95fb6ada7 100644 --- a/Modules/checkingUpdate.py +++ b/Modules/checkingUpdate.py @@ -131,7 +131,7 @@ def is_zigate_firmware_available(self, currentMajorVersion, currentFirmwareVersi def is_internet_available(): try: - response = requests.get("http://www.google.com", timeout=3) + response = requests.get("https://www.google.com", timeout=3) # Check if the status code is a success code (2xx) return response.status_code == 200 except requests.ConnectionError: diff --git a/Modules/heartbeat.py b/Modules/heartbeat.py index 065a3ef80..18a78534d 100755 --- a/Modules/heartbeat.py +++ b/Modules/heartbeat.py @@ -47,6 +47,7 @@ ReadAttributeRequest_0402, ReadAttributeRequest_0405, ReadAttributeRequest_0702_0000, + ReadAttributeRequest_0702_0017, ReadAttributeRequest_0702_PC321, ReadAttributeRequest_0702_ZLinky_TIC, ReadAttributeRequest_ff66, @@ -344,7 +345,9 @@ def pollingManufSpecificDevices(self, NwkId, HB): "HumiPollingFreq": ReadAttributeRequest_0405, "BattPollingFreq": ReadAttributeRequest_0001, "ZLinkyIndexes": ReadAttributeReq_Scheduled_ZLinky, # Based on a specific time - "ZLinkyPollingPTEC": ReadAttributeReq_Scheduled_ZLinky # Every 15' by default + "ZLinkyPollingPTEC": ReadAttributeReq_Scheduled_ZLinky, # Every 15' by default + "InletTempPolling": ReadAttributeRequest_0702_0017, # Retreive Inlet Temperature + } if "Param" not in self.ListOfDevices[NwkId]: diff --git a/Modules/readAttributes.py b/Modules/readAttributes.py index 9920351bb..c52f9637f 100644 --- a/Modules/readAttributes.py +++ b/Modules/readAttributes.py @@ -1333,6 +1333,34 @@ def ReadAttributeRequest_0702_0000(self, key): self.log.logging("ReadAttributes", "Debug", "Request Summation on 0x0702 cluster: " + key + " EPout = " + EPout, nwkid=key) ReadAttributeReq(self, key, ZIGATE_EP, EPout, "0702", listAttributes, ackIsDisabled=is_ack_tobe_disabled(self, key)) + +def ReadAttributeRequest_0702_0017(self, key): + """ + Reads the InletTemperature (Attribute 0x0017) from the Metering cluster (0x0702). + + Parameters: + self: The instance of the class. + key: The network identifier for the device. + """ + + # Define the cluster and attribute + cluster_id = "0702" + attributes_list = [0x0017,] + + # Get the list of endpoints for the cluster + endpoints = getListOfEpForCluster(self, key, cluster_id) + for endpoint in endpoints: + self.log.logging( + "ReadAttributes", + "Debug", + f"Requesting InletTemperature (Attribute {attributes_list}) on cluster {cluster_id} for key {key}, EP = {endpoint}.", + nwkid=key + ) + + # Send the read attribute request + ReadAttributeReq(self, key, ZIGATE_EP, endpoint, cluster_id, attributes_list, ackIsDisabled=is_ack_tobe_disabled(self, key)) + + def ReadAttributeRequest_0702_multiplier_divisor(self, key): ListOfEp = getListOfEpForCluster(self, key, "0702") for EPout in ListOfEp: diff --git a/Modules/tools.py b/Modules/tools.py index aea21b899..4ced7cdde 100644 --- a/Modules/tools.py +++ b/Modules/tools.py @@ -108,6 +108,10 @@ def getListOfEpForCluster(self, NwkId, SearchCluster): oldFashion = ( "ClusterType" in self.ListOfDevices[NwkId] and self.ListOfDevices[NwkId]["ClusterType"] not in ({}, "") ) for Ep in list(self.ListOfDevices[NwkId]["Ep"].keys()): + # check that is not a Fake Ep + if is_fake_ep(self, NwkId, Ep): + continue + if SearchCluster not in self.ListOfDevices[NwkId]["Ep"][Ep]: continue diff --git a/Zigbee/zclDecoders.py b/Zigbee/zclDecoders.py index 430055492..ae529bddc 100644 --- a/Zigbee/zclDecoders.py +++ b/Zigbee/zclDecoders.py @@ -6,7 +6,6 @@ import struct -from distutils.command.build import build from os import stat from Modules.tools import (is_direction_to_client, is_direction_to_server, diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 000000000..b3ddfcdb1 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,3 @@ +sonar.issue.ignore.multicriteria=e1 +sonar.issue.ignore.multicriteria.e1.ruleKey=python:S5332 +sonar.issue.ignore.multicriteria.e1.resourceKey=**