diff --git a/Modules/command.py b/Modules/command.py index d38834ae8..25f631f6c 100644 --- a/Modules/command.py +++ b/Modules/command.py @@ -694,9 +694,9 @@ def mgtCommand(self, Devices, Unit, Command, Level, Color): elif DeviceType == "ThermoOnOff": if "Model" in self.ListOfDevices[NWKID] and self.ListOfDevices[NWKID]["Model"] in ("eTRV0100"): - danfoss_on_off(self, NWKID, 0x01) + danfoss_on_off(self, NWKID, 0x01) else: - tuya_trv_onoff(self, NWKID, 0x01) + tuya_trv_onoff(self, NWKID, 0x01) UpdateDevice_v2(self, Devices, Unit, 1, "On", BatteryLevel, SignalLevel, ForceUpdate_=forceUpdateDev) elif DeviceType == "ShutterCalibration": @@ -1360,6 +1360,8 @@ def mgtCommand(self, Devices, Unit, Command, Level, Color): UpdateDevice_v2(self, Devices, Unit, 1, str(Level), BatteryLevel, SignalLevel, str(Color)) + + def get_previous_switch_level(self, NwkId, Ep): if NwkId not in self.ListOfDevices: diff --git a/Modules/domoMaj.py b/Modules/domoMaj.py index fd1b9a76e..63549d495 100644 --- a/Modules/domoMaj.py +++ b/Modules/domoMaj.py @@ -9,10 +9,15 @@ """ from Modules.domoticzAbstractLayer import (domo_check_unit, + domo_read_Device_Idx, domo_read_nValue_sValue, + domo_read_Options, domo_read_SwitchType_SubType_Type, domo_update_api, - find_widget_unit_from_WidgetID) + find_widget_unit_from_WidgetID, + is_dimmable_blind, + is_dimmable_light, + is_dimmable_switch) from Modules.domoTools import (RetreiveSignalLvlBattery, RetreiveWidgetTypeList, TypeFromCluster, UpdateDevice_v2, remove_bad_cluster_type_entry) @@ -23,98 +28,45 @@ get_tarif_color, zlinky_sum_all_indexes) from Zigbee.zdpCommands import zdp_IEEE_address_request +WIDGET_TO_BYPASS_EP_MATCH = ("XCube", "Aqara", "DSwitch", "DButton", "DButton_3") -def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Color_=""): + + + +def MajDomoDevice(self, Devices, NwkId, Ep, ClusterId, value, Attribute_="", Color_=""): """ MajDomoDevice Update domoticz device accordingly to Type found in EP and value/Color provided """ - # Sanity Checks - if self.CommiSSionning and NWKID not in self.ListOfDevices: - return - - if NWKID not in self.ListOfDevices: - self.log.logging("Widget", "Error", f"MajDomoDevice - {NWKID} not known", NWKID) - zigpy_plugin_sanity_check(self, NWKID) - return - - if "Health" in self.ListOfDevices.get(NWKID, {}) and self.ListOfDevices[NWKID]["Health"] == "Disabled": - # If the device has been disabled, just drop the message - self.log.logging("Widget", "Debug", f"MajDomoDevice - disabled device: {NWKID}/{Ep} dropping message", NWKID) - return - - if Ep not in self.ListOfDevices.get(NWKID, {}).get("Ep", []): - self.log.logging("Widget", "Error", f"MajDomoDevice - {NWKID}/{Ep} not known Endpoint", NWKID) + if not is_time_to_domo_update(self, NwkId, Ep): return - - check_and_update_db_status(self, NWKID) - - device_status = self.ListOfDevices.get(NWKID, {}).get("Status", "") - if device_status != "inDB": - self.log.logging("Widget", "Log", f"MajDomoDevice NwkId: {NWKID} status: {device_status} not inDB. Requesting IEEE for possible reconnection", NWKID) - - if not zigpy_plugin_sanity_check(self, NWKID): - # Broadcast to 0xfffd: macRxOnWhenIdle = TRUE - zdp_IEEE_address_request(self, 'fffd', NWKID, u8RequestType="00", u8StartIndex="00") - return - - device_id_ieee = self.ListOfDevices.get(NWKID, {}).get("IEEE") - if device_id_ieee is None: - self.log.logging("Widget", "Error", f"MajDomoDevice - no IEEE for {NWKID}", NWKID) - return - - model_name = self.ListOfDevices[NWKID].get("Model", "") + model_name = self.ListOfDevices.get(NwkId, {}).get("Model", "") + device_id_ieee = self.ListOfDevices.get(NwkId, {}).get("IEEE") + self.log.logging( "Widget", "Debug", "MajDomoDevice NwkId: %s Ep: %s ClusterId: %s Value: %s ValueType: %s Attribute: %s Color: %s ModelName: %s" % ( - NWKID, Ep, clusterID, value, type(value), Attribute_, Color_, model_name), NWKID, ) + NwkId, Ep, ClusterId, value, type(value), Attribute_, Color_, model_name), NwkId, ) # Get the CluserType ( Action type) from Cluster Id - ClusterType = TypeFromCluster(self, clusterID) - self.log.logging("Widget", "Debug", "------> ClusterType = " + str(ClusterType), NWKID) + ClusterType = TypeFromCluster(self, ClusterId) + self.log.logging("Widget", "Debug", "------> ClusterType = " + str(ClusterType), NwkId) - ClusterTypeList = RetreiveWidgetTypeList(self, Devices, NWKID) - self.log.logging("Widget", "Debug", "------> ClusterTypeList = " + str(ClusterTypeList), NWKID) + ClusterTypeList = RetreiveWidgetTypeList(self, Devices, NwkId) + self.log.logging("Widget", "Debug", "------> ClusterTypeList = " + str(ClusterTypeList), NwkId) if len(ClusterTypeList) == 0: # We don't have any widgets associated to the NwkId return - WidgetByPassEpMatch = ("XCube", "Aqara", "DSwitch", "DButton", "DButton_3") - + # Look for each entry in ClusterTypeList for WidgetEp, WidgetId, WidgetType in ClusterTypeList: - if WidgetEp == "00": - # Old fashion - WidgetEp = "01" # Force to 01 + _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, model_name, ClusterType, ClusterTypeList, ClusterId, value, Attribute_, Color_, WidgetEp, WidgetId, WidgetType ) - self.log.logging( "Widget", "Debug", "----> processing WidgetEp: %s, WidgetId: %s, WidgetType: %s" % ( - WidgetEp, WidgetId, WidgetType), NWKID, ) - - if WidgetType not in WidgetByPassEpMatch and WidgetEp != Ep: - # We need to make sure that we are on the right Endpoint - self.log.logging( "Widget", "Debug", "------> skiping this WidgetEp as do not match Ep : %s %s" % ( - WidgetEp, Ep), NWKID,) - continue + +def _domo_maj_one_cluster_type_entry( self, Devices, NwkId, Ep, device_id_ieee, model_name, ClusterType, ClusterTypeList, ClusterId, value, Attribute_, Color_, WidgetEp, WidgetId, WidgetType ): - DeviceUnit = find_widget_unit_from_WidgetID(self, Devices, WidgetId ) - - if DeviceUnit is None: - self.log.logging( "Widget", "Error", "Device %s not found !!!" % WidgetId, NWKID) - # House keeping, we need to remove this bad clusterType - if remove_bad_cluster_type_entry(self, NWKID, Ep, clusterID, WidgetId ): - self.log.logging( "Widget", "Log", "WidgetID %s not found, successfully remove the entry from device" % WidgetId, NWKID) - else: - self.log.logging( "Widget", "Error", "WidgetID %s not found, unable to remove the entry from device" % WidgetId, NWKID) - continue - - elif domo_check_unit(self, Devices, device_id_ieee, DeviceUnit) not in Devices: - continue - - prev_nValue, prev_sValue = domo_read_nValue_sValue(self, Devices, device_id_ieee, DeviceUnit) - switchType, Subtype, _ = domo_read_SwitchType_SubType_Type(self, Devices, device_id_ieee, DeviceUnit) - - # device_id_ieee is the DeviceID (IEEE) - # DeviceUnit is the Device unit + # device_unit is the Device unit # WidgetEp is the Endpoint to which the widget is linked to # WidgetId is the Device ID # WidgetType is the Widget Type at creation @@ -125,30 +77,54 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col # Attribute_ : If used This is the Attribute from readCluster. Will help to route to the right action # Color_ : If used This is the color value to be set + self.log.logging( "Widget", "Debug", "_domo_maj_one_cluster_type_entry WidgetEp: %s, WidgetId: %s, WidgetType: %s" % ( + WidgetEp, WidgetId, WidgetType), NwkId, ) + + if WidgetEp == "00": + # Old fashion / keep it for backward compatibility + WidgetEp = "01" # Force to 01 + + if WidgetType not in WIDGET_TO_BYPASS_EP_MATCH and WidgetEp != Ep: + # We need to make sure that we are on the right Endpoint + self.log.logging( "Widget", "Debug", "------> skiping this WidgetEp as do not match Ep : %s %s" % (WidgetEp, Ep), NwkId,) + return + + device_unit = retreive_device_unit( self, Devices, NwkId, Ep, device_id_ieee, ClusterId, WidgetId ) + if device_unit is None: + return + + prev_nValue, prev_sValue = domo_read_nValue_sValue(self, Devices, device_id_ieee, device_unit) + switchType, Subtype, _ = domo_read_SwitchType_SubType_Type(self, Devices, device_id_ieee, device_unit) + self.log.logging( "Widget", "Debug", "------> ClusterType: %s WidgetEp: %s WidgetId: %s WidgetType: %s Attribute_: %s" % ( - ClusterType, WidgetEp, WidgetId, WidgetType, Attribute_), NWKID, ) + ClusterType, WidgetEp, WidgetId, WidgetType, Attribute_), NwkId, ) - SignalLevel, BatteryLevel = RetreiveSignalLvlBattery(self, NWKID) - self.log.logging("Widget", "Debug", "------> SignalLevel: %s , BatteryLevel: %s" % (SignalLevel, BatteryLevel), NWKID) + SignalLevel, BatteryLevel = RetreiveSignalLvlBattery(self, NwkId) + self.log.logging("Widget", "Debug", "------> SignalLevel: %s , BatteryLevel: %s" % (SignalLevel, BatteryLevel), NwkId) if ClusterType == "Alarm" and WidgetType == "Alarm_ZL" and Attribute_ == "0005": # This is Alarm3 for ZLinky Intensity alert value, text = value.split("|") nValue = int(value) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, text, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, text, BatteryLevel, SignalLevel) if ClusterType == "Alarm" and WidgetType == "Alarm_ZL2" and Attribute_ == "0001": # Notification Next Day Color and Peak tuple_value = value.split("|") if len(tuple_value) != 2: - self.log.logging( "Widget", "Error", "------> Expecting 2 values got %s in Value = %s for Nwkid: %s Attribute: %s" % ( - len(tuple_value), value, NWKID, Attribute_), NWKID, ) - continue + self.log.logging( + "Widget", + "Error", + "------> Expecting 2 values got %s in Value = %s for NwkId: %s Attribute: %s" % ( + len(tuple_value), value, NwkId, Attribute_), + NwkId, + ) + return value, text = tuple_value nValue = int(value) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, text, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, text, BatteryLevel, SignalLevel) if ClusterType == "Alarm" and WidgetType == "Alarm_ZL3" and Attribute_ == "0020": if value is None or len(value) == 0: @@ -218,18 +194,17 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col # Unknow nValue = 3 sValue = "Unknown" - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if "Ampere" in ClusterType and WidgetType == "Ampere" and Attribute_ == "0508": sValue = "%s" % (round(float(value), 2)) - self.log.logging("Widget", "Debug", "------> Ampere : %s" % sValue, NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, str(sValue), BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> Ampere : %s" % sValue, NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, str(sValue), BatteryLevel, SignalLevel) if "Ampere" in ClusterType and WidgetType == "Ampere3" and Attribute_ in ("0508", "0908", "0a08"): # Retreive the previous values sValue = "%s;%s;%s" % (0, 0, 0) - - ampere1, ampere2, ampere3 = retrieve_data_from_current(self, Devices, device_id_ieee, DeviceUnit, "%s;%s;%s") + ampere1, ampere2, ampere3 = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, "0;0;0") if ampere2 == ampere3 == '65535.0': self.log.logging("Widget", "Debug", "------> Something going wrong ..... ampere %s %s %s" %(ampere1, ampere2, ampere3)) ampere2 = '0.0' @@ -245,16 +220,16 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col # Line 3 sValue = "%s;%s;%s" % (ampere1, ampere2, ampere) - self.log.logging("Widget", "Debug", "------> Ampere3 : %s from Attribute: %s" % (sValue, Attribute_), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, str(sValue), BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> Ampere3 : %s from Attribute: %s" % (sValue, Attribute_), NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, str(sValue), BatteryLevel, SignalLevel) if "PWFactor" == ClusterType and WidgetType == "PowerFactor": self.log.logging("Widget", "Debug", "PowerFactor %s WidgetType: %s Value: %s (%s)" % ( - NWKID, WidgetType, value, type(value)), NWKID) + NwkId, WidgetType, value, type(value)), NwkId) nValue = round(value, 1) sValue = str(nValue) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if "Power" in ClusterType: # Instant Power/Watts # Power and Meter usage are triggered only with the Instant Power usage. @@ -262,74 +237,72 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col # such information is stored on the data structuture and here we will retreive it. # value is expected as String - if WidgetType == "Power" and (Attribute_ in ("", "050f") or clusterID == "000c"): # kWh + if WidgetType == "Power" and (Attribute_ in ("", "050f") or ClusterId == "000c"): # kWh if (( isinstance( value, (int, float)) and value < 0) or (float(value) < 0) ) and is_PowerNegative_widget( ClusterTypeList): - self.log.logging("Widget", "Debug", "------>There is a PowerNegative widget and the value is negative. Skiping here", NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, "0", BatteryLevel, SignalLevel) - continue + self.log.logging("Widget", "Debug", "------>There is a PowerNegative widget and the value is negative. Skiping here", NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, "0", BatteryLevel, SignalLevel) + return nValue = round(float(value), 2) sValue = value - self.log.logging("Widget", "Debug", "------>Power : %s" % sValue, NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, str(sValue), BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------>Power : %s" % sValue, NwkId) + UpdateDevice_v2(self, Devices, device_unit, nValue, str(sValue), BatteryLevel, SignalLevel) if WidgetType == "ProdPower" and Attribute_ == "": if value > 0: - self.log.logging("Widget", "Debug", "------>the value is Positive. Skiping here", NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, "0", BatteryLevel, SignalLevel) - continue + self.log.logging("Widget", "Debug", "------>the value is Positive. Skiping here", NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, "0", BatteryLevel, SignalLevel) + return nValue = abs( round(float(value), 2) ) sValue = abs(value) - self.log.logging("Widget", "Debug", "------>PowerNegative : %s" % sValue, NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, str(sValue), BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------>PowerNegative : %s" % sValue, NwkId) + UpdateDevice_v2(self, Devices, device_unit, nValue, str(sValue), BatteryLevel, SignalLevel) if WidgetType == "P1Meter" and Attribute_ == "0000": - self.log.logging("Widget", "Debug", "------> P1Meter : %s (%s)" % (value, type(value)), NWKID) + self.log.logging("Widget", "Debug", "------> P1Meter : %s (%s)" % (value, type(value)), NwkId) # P1Meter report Instant and Cummulative Power. # We need to retreive the Cummulative Power. - cur_usage1, cur_usage2, cur_return1, cur_return2, _, _ = retrieve_data_from_current(self, Devices, device_id_ieee, DeviceUnit, "0;0;0;0;0;0") - + cur_usage1, cur_usage2, cur_return1, cur_return2, cur_cons, cur_prod = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, "0;0;0;0;0;0") usage1 = usage2 = return1 = return2 = cons = prod = 0 - - if "0702" in self.ListOfDevices[NWKID]["Ep"][Ep] and "0400" in self.ListOfDevices[NWKID]["Ep"][Ep]["0702"]: - cons = round(float(self.ListOfDevices[NWKID]["Ep"][Ep]["0702"]["0400"]), 2) + if "0702" in self.ListOfDevices[NwkId]["Ep"][Ep] and "0400" in self.ListOfDevices[NwkId]["Ep"][Ep]["0702"]: + cons = round(float(self.ListOfDevices[NwkId]["Ep"][Ep]["0702"]["0400"]), 2) usage1 = int(float(value)) sValue = "%s;%s;%s;%s;%s;%s" % (usage1, usage2, return1, return2, cons, prod) - self.log.logging("Widget", "Debug", "------> P1Meter : " + sValue, NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, str(sValue), BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> P1Meter : " + sValue, NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, str(sValue), BatteryLevel, SignalLevel) if ( WidgetType == "P1Meter_ZL" - and model_name in ZLINK_CONF_MODEL - and Attribute_ in ( "0100", "0102", "0104", "0106", "0108", "010a") + and "Model" in self.ListOfDevices[NwkId] + and self.ListOfDevices[NwkId]["Model"] in ZLINK_CONF_MODEL and Attribute_ in ( "0100", "0102", "0104", "0106", "0108", "010a") ): if Attribute_ != "050f" and Ep == "01" and Attribute_ not in ("0100", "0102"): # Ep = 01, so we store Base, or HP,HC, or BBRHCJB, BBRHPJB - continue + return if Attribute_ != "050f" and Ep == "f2" and Attribute_ not in ("0104", "0106"): # Ep = f2, so we store BBRHCJW, BBRHPJW - continue + return if Attribute_ != "050f" and Ep == "f3" and Attribute_ not in ("0108", "010a"): # Ep == f3, so we store BBRHCJR, BBRHPJR - continue + return - tarif_color = get_tarif_color( self, NWKID ) + tarif_color = get_tarif_color( self, NwkId ) self.log.logging("ZLinky", "Debug", "------> P1Meter_ZL : %s Attribute: %s Color: %s (%s)" % ( - value, Attribute_, tarif_color, type(value)), NWKID) + value, Attribute_, tarif_color, type(value)), NwkId) # P1Meter report Instant and Cummulative Power. # We need to retreive the Cummulative Power. - cur_usage1, cur_usage2, cur_return1, cur_return2, cur_cons, cur_prod = retrieve_data_from_current(self, Devices, device_id_ieee, DeviceUnit, "0;0;0;0;0;0") + cur_usage1, cur_usage2, cur_return1, cur_return2, cur_cons, cur_prod = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, "0;0;0;0;0;0") usage1 = usage2 = return1 = return2 = cons = prod = 0 - self.log.logging("ZLinky", "Debug", "------> P1Meter_ZL (%s): retreive value: %s;%s;%s;%s;%s;%s" % (Ep, cur_usage1, cur_usage2, cur_return1, cur_return2, cur_cons, cur_prod), NWKID) + self.log.logging("ZLinky", "Debug", "------> P1Meter_ZL (%s): retreive value: %s;%s;%s;%s;%s;%s" % (Ep, cur_usage1, cur_usage2, cur_return1, cur_return2, cur_cons, cur_prod), NwkId) # We are so receiving a usage update - self.log.logging( "ZLinky", "Debug", "------> P1Meter_ZL : Trigger by Index Update %s Ep: %s" % (Attribute_, Ep), NWKID, ) - cons = get_instant_power(self, NWKID) + self.log.logging( "ZLinky", "Debug", "------> P1Meter_ZL : Trigger by Index Update %s Ep: %s" % (Attribute_, Ep), NwkId, ) + cons = get_instant_power(self, NwkId) if Attribute_ in ("0000", "0100", "0104", "0108"): # Usage 1 usage1 = int(round(float(value), 0)) @@ -338,7 +311,7 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col return2 = cur_return2 if usage1 == cur_usage1: # Skip update as there is no consumption - continue + return elif Attribute_ in ("0102", "0106", "010a"): # Usage 2 @@ -348,41 +321,42 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col return2 = cur_return2 if usage2 == cur_usage2: # Skip update as there is no consumption - continue + return if tarif_color == "Blue" and Ep != "01" or tarif_color == "White" and Ep != "f2" or tarif_color == "Red" and Ep != "f3": cons = 0.0 sValue = "%s;%s;%s;%s;%s;%s" % (usage1, usage2, return1, return2, cons, cur_prod) - self.log.logging("ZLinky", "Debug", "------> P1Meter_ZL (%s): %s" % (Ep, sValue), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, str(sValue), BatteryLevel, SignalLevel) + self.log.logging("ZLinky", "Debug", "------> P1Meter_ZL (%s): %s" % (Ep, sValue), NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, str(sValue), BatteryLevel, SignalLevel) if "Meter" in ClusterType: # Meter Usage. if WidgetType == "GazMeter" and Attribute_ == "0000": # Gaz Meter sValue = "%s" %value - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) elif WidgetType == "Counter" and Attribute_ == "0000": sValue = "%s" %int(value) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) elif WidgetType == "ConsoMeter" and Attribute_ == "0000": # Consummed Energy sValue = "%s" %int(value) - self.log.logging("Widget", "Debug", "------>ConsoMeter : %s" % sValue, NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------>ConsoMeter : %s" % sValue, NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) elif WidgetType == "ProdMeter" and Attribute_ == "0001": # Produced Energy injected sValue = "%s" %int(value) - self.log.logging("Widget", "Debug", "------>ProdMeter : %s" % sValue, NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------>ProdMeter : %s" % sValue, NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) # value is string an represent the Instant Usage elif ( - model_name in ZLINK_CONF_MODEL + "Model" in self.ListOfDevices[ NwkId ] + and self.ListOfDevices[ NwkId ]["Model"] in ZLINK_CONF_MODEL and WidgetType == "Meter" and ( Attribute_ == "0000" @@ -391,35 +365,35 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col or ( Attribute_ in ("0108", "010a") and Ep == "f3") ) ): - check_set_meter_widget( self, Devices, device_id_ieee, DeviceUnit, 0) - instant, _summation = retrieve_data_from_current(self, Devices, device_id_ieee, DeviceUnit, "0;0") - summation = round(float(zlinky_sum_all_indexes( self, NWKID )), 2) + check_set_meter_widget( self, Devices, device_id_ieee, device_unit, 0) + instant, _summation = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, "0;0") + summation = round(float(zlinky_sum_all_indexes( self, NwkId )), 2) self.log.logging("ZLinky", "Debug", "------> Summation for Meter : %s" %summation) sValue = "%s;%s" % (instant, summation) self.log.logging("ZLinky", "Debug", "------> : " + sValue) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) elif WidgetType == "Meter" and Attribute_ == "050f": # We receive Instant Power - check_set_meter_widget( self, Devices, device_id_ieee, DeviceUnit, 0) - _instant, summation = retrieve_data_from_current(self, Devices, device_id_ieee, DeviceUnit, "0;0") + check_set_meter_widget(self, Devices, device_id_ieee, device_unit, 0) + _instant, summation = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, "0;0") instant = round(float(value), 2) sValue = "%s;%s" % (instant, summation) self.log.logging("Widget", "Debug", "------> : " + sValue) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) - elif (WidgetType == "Meter" and Attribute_ == "") or (WidgetType == "Power" and clusterID == "000c"): # kWh + elif (WidgetType == "Meter" and Attribute_ == "") or (WidgetType == "Power" and ClusterId == "000c"): # kWh # We receive Instant # Let's check if we have Summation in the datastructutre summation = 0 if ( - "0702" in self.ListOfDevices[NWKID]["Ep"][Ep] - and "0000" in self.ListOfDevices[NWKID]["Ep"][Ep]["0702"] - and self.ListOfDevices[NWKID]["Ep"][Ep]["0702"]["0000"] not in ({}, "", "0") + "0702" in self.ListOfDevices[NwkId]["Ep"][Ep] + and "0000" in self.ListOfDevices[NwkId]["Ep"][Ep]["0702"] + and self.ListOfDevices[NwkId]["Ep"][Ep]["0702"]["0000"] not in ({}, "", "0") ): - # summation = int(self.ListOfDevices[NWKID]['Ep'][Ep]['0702']['0000']) - summation = self.ListOfDevices[NWKID]["Ep"][Ep]["0702"]["0000"] + # summation = int(self.ListOfDevices[NwkId]['Ep'][Ep]['0702']['0000']) + summation = self.ListOfDevices[NwkId]["Ep"][Ep]["0702"]["0000"] instant = round(float(value), 2) # Did we get Summation from Data Structure @@ -428,17 +402,15 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col sValue = "%s;%s" % (instant, summation) # We got summation from Device, let's check that EnergyMeterMode is # correctly set to 0, if not adjust - check_set_meter_widget( self, Devices, device_id_ieee, DeviceUnit, 0) - + check_set_meter_widget( self, Devices, device_id_ieee, device_unit, 0) else: sValue = "%s;" % (instant) - check_set_meter_widget( self, Devices, device_id_ieee, DeviceUnit, 1) - + check_set_meter_widget( self, Devices, device_id_ieee, device_unit, 1) # No summation retreive, so we make sure that EnergyMeterMode is # correctly set to 1 (compute), if not adjust self.log.logging("Widget", "Debug", "------> : " + sValue) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) if "WaterCounter" in ClusterType and WidgetType == "WaterCounter": # /json.htm?type=command¶m=udevice&idx=IDX&nvalue=0&svalue=INCREMENT @@ -447,42 +419,37 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col # will increment the counter value by 1. # To reset an incremental counter, set the svalue to a negative integer equal to the current total of the counter. sValue = "%s" %value - self.log.logging("Widget", "Debug", "WaterCounter ------> : %s" %sValue, NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + self.log.logging("Widget", "Log", "WaterCounter ------> : %s" %sValue, NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - if "Voltage" in ClusterType: # Volts - # value is str - if WidgetType == "Voltage" and Attribute_ == "": - nValue = round(float(value), 2) - sValue = "%s;%s" % (nValue, nValue) - self.log.logging("Widget", "Debug", "------> : " + sValue, NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) - - if "ThermoSetpoint" in ClusterType: # Thermostat SetPoint - # value is a str - if WidgetType == "ThermoSetpoint" and Attribute_ in ("4003", "0012"): - setpoint = round(float(value), 2) - # Normalize SetPoint value with 2 digits - nValue = 0 - sValue = str_round(float(setpoint), 2) # 2 decimals - self.log.logging("Widget", "Debug", "------> Thermostat nValue: %s SetPoint: %s sValue: %s" % ( - 0, setpoint, sValue), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) + if "Voltage" in ClusterType and (WidgetType == "Voltage" and Attribute_ == ""): + nValue = round(float(value), 2) + sValue = "%s;%s" % (nValue, nValue) + self.log.logging("Widget", "Debug", "------> : " + sValue, NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) + + if "ThermoSetpoint" in ClusterType and (WidgetType == "ThermoSetpoint" and Attribute_ in ("4003", "0012")): + setpoint = round(float(value), 2) + # Normalize SetPoint value with 2 digits + nValue = 0 + sValue = str_round(float(setpoint), 2) # 2 decimals + self.log.logging("Widget", "Debug", "------> Thermostat Setpoint: %s %s" % (0, setpoint), NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) if "Analog" in ClusterType: if WidgetType == "Voc" and Attribute_ == "": sValue = str( value ) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, sValue, BatteryLevel, SignalLevel) elif WidgetType == "Motionac01" and Ep == "01": # Motionac01 if value <= 7: nValue= value + 1 sValue = str(nValue * 10) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) elif WidgetType == "Analog": # Analog Value from Analog Input cluster - UpdateDevice_v2(self, Devices, DeviceUnit, 0, value, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, value, BatteryLevel, SignalLevel) if ("XCube" in ClusterType) or ("Analog" in ClusterType and model_name in ("lumi.sensor_cube.aqgl01", "lumi.sensor_cube")): # XCube Aqara or Xcube if WidgetType == "Aqara" : @@ -490,13 +457,13 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col "Widget", "Debug", "--------> XCube Aqara Ep: %s Attribute_: %s Value: %s = " % (Ep, Attribute_, value), - NWKID, + NwkId, ) if Ep == "02" and Attribute_ == "": # Magic Cube Aqara - self.log.logging("Widget", "Debug", "----------> XCube update device with data = " + str(value), NWKID) + self.log.logging("Widget", "Debug", "----------> XCube update device with data = " + str(value), NwkId) nValue = int(value) sValue = value - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) elif Ep == "03": # Magic Cube Aqara Rotation if Attribute_ == "0055": # Rotation Angle @@ -504,15 +471,15 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col "Widget", "Debug", "----------> XCube update Rotaion Angle with data = " + str(value), - NWKID, + NwkId, ) # Update Text widget ( unit + 1 ) nValue = 0 sValue = value - UpdateDevice_v2(self, Devices, DeviceUnit + 1, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit + 1, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) else: - self.log.logging("Widget", "Debug", "----------> XCube update with data = " + str(value), NWKID) + self.log.logging("Widget", "Debug", "----------> XCube update with data = " + str(value), NwkId) nValue = int(value) sValue = value if nValue == 80: @@ -525,53 +492,53 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col "Widget", "Debug", "--------> XCube update device with data = %s , nValue: %s sValue: %s" % (value, nValue, sValue), - NWKID, + NwkId, ) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) elif WidgetType == "XCube" and Ep == "02": # cube xiaomi if value == "0000": # shake state = "10" data = "01" - UpdateDevice_v2(self, Devices, DeviceUnit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) elif value in ("0204", "0200", "0203", "0201", "0202", "0205"): state = "50" data = "05" - UpdateDevice_v2(self, Devices, DeviceUnit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) elif value in ("0103", "0100", "0104", "0101", "0102", "0105"): # Slide/M%ove state = "20" data = "02" - UpdateDevice_v2(self, Devices, DeviceUnit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) elif value == "0003": # Free Fall state = "70" data = "07" - UpdateDevice_v2(self, Devices, DeviceUnit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) elif "0004" <= value <= "0059": # 90° state = "30" data = "03" - UpdateDevice_v2(self, Devices, DeviceUnit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) elif value >= "0060": # 180° state = "90" data = "09" - UpdateDevice_v2(self, Devices, DeviceUnit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) if "Valve" in ClusterType and (WidgetType == "Valve" and Attribute_ in ("026d", "4001", "0008")): nValue = round(value, 1) sValue = str(nValue) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if "ThermoMode" in ClusterType: # Thermostat Mode self.log.logging("Widget", "Debug", "ThermoMode %s WidgetType: %s Value: %s (%s) Attribute_: %s" % ( - NWKID, WidgetType, value, type(value), Attribute_), NWKID) + NwkId, WidgetType, value, type(value), Attribute_), NwkId) if WidgetType == "ThermoModeEHZBRTS" and Attribute_ == "e010": # Thermostat Wiser # value is str - self.log.logging("Widget", "Debug", "------> EHZBRTS Schneider Thermostat Mode %s" % value, NWKID) + self.log.logging("Widget", "Debug", "------> EHZBRTS Schneider Thermostat Mode %s" % value, NwkId) THERMOSTAT_MODE = { 0: "00", # Mode Off 1: "10", # Manual @@ -585,43 +552,43 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col if _mode in THERMOSTAT_MODE: nValue = _mode sValue = THERMOSTAT_MODE[_mode] - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif WidgetType == "HeatingSwitch" and Attribute_ == "001c": - self.log.logging("Widget", "Debug", "------> HeatingSwitch %s" % value, NWKID) + self.log.logging("Widget", "Debug", "------> HeatingSwitch %s" % value, NwkId) if value == 0: - UpdateDevice_v2(self, Devices, DeviceUnit, 0, "Off", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, "Off", BatteryLevel, SignalLevel) elif value == 4: - UpdateDevice_v2(self, Devices, DeviceUnit, 1, "On", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 1, "On", BatteryLevel, SignalLevel) elif WidgetType == "HeatingStatus" and Attribute_ == "0124": - self.log.logging("Widget", "Debug", "------> HeatingStatus %s" % value, NWKID) + self.log.logging("Widget", "Debug", "------> HeatingStatus %s" % value, NwkId) if value == 0: - UpdateDevice_v2(self, Devices, DeviceUnit, 0, "Not Heating", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, "Not Heating", BatteryLevel, SignalLevel) elif value == 1: - UpdateDevice_v2(self, Devices, DeviceUnit, 1, "Heating", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 1, "Heating", BatteryLevel, SignalLevel) elif WidgetType == "ThermoOnOff" and Attribute_ == "6501": - self.log.logging("Widget", "Debug", "------> Thermo On/Off %s" % value, NWKID) + self.log.logging("Widget", "Debug", "------> Thermo On/Off %s" % value, NwkId) if value == 0: - UpdateDevice_v2(self, Devices, DeviceUnit, 0, "Off", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, "Off", BatteryLevel, SignalLevel) elif value == 1: - UpdateDevice_v2(self, Devices, DeviceUnit, 1, "On", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 1, "On", BatteryLevel, SignalLevel) elif WidgetType == "HACTMODE" and Attribute_ == "e011": # Wiser specific Fil Pilote # value is str - self.log.logging("Widget", "Debug", "------> ThermoMode HACTMODE: %s" % (value), NWKID) + self.log.logging("Widget", "Debug", "------> ThermoMode HACTMODE: %s" % (value), NwkId) THERMOSTAT_MODE = {0: "10", 1: "20"} # Conventional heater # fip enabled heater _mode = ((int(value, 16) - 0x80) >> 1) & 1 if _mode in THERMOSTAT_MODE: sValue = THERMOSTAT_MODE[_mode] nValue = _mode + 1 - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) - elif WidgetType == "LegranCableMode" and clusterID == "fc01": # Legrand + elif WidgetType == "LegranCableMode" and ClusterId == "fc01": # Legrand # value is str - self.log.logging("Widget", "Debug", "------> Legrand Mode: %s" % (value), NWKID) + self.log.logging("Widget", "Debug", "------> Legrand Mode: %s" % (value), NwkId) THERMOSTAT_MODE = {0x0100: "10", 0x0200: "20"} # Conventional heater # fip enabled heater _mode = int(value, 16) @@ -630,11 +597,11 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col sValue = THERMOSTAT_MODE[_mode] nValue = int(sValue) // 10 - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif WidgetType == "FIP" and Attribute_ in ("0000", "e020"): # Wiser specific Fil Pilote # value is str - self.log.logging("Widget", "Debug", "------> ThermoMode FIP: %s" % (value), NWKID) + self.log.logging("Widget", "Debug", "------> ThermoMode FIP: %s" % (value), NwkId) FIL_PILOT_MODE = { 0: "10", 1: "20", # confort -1 @@ -650,117 +617,118 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col sValue = FIL_PILOT_MODE[_mode] if Attribute_ == "e020": # Wiser specific Fil Pilote - ep_data = self.ListOfDevices[NWKID].get("Ep", {}).get(Ep, {}).get("0201", {}).get("e011", "") - - if "0201" in ep_data and "e011" in ep_data and ep_data["e011"] != {} and ep_data["e011"] != "": - _value_mode_hact = ep_data["e011"] - _mode_hact = ((int(_value_mode_hact, 16) - 0x80)) & 1 - - if _mode_hact == 0: - self.log.logging("Widget", "Debug", "------> Disable FIP widget: %s" % (value), NWKID) - nValue = 0 - - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) - - elif clusterID == "fc40": # Legrand FIP - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + if "0201" in self.ListOfDevices[NwkId]["Ep"][Ep]: + if "e011" in self.ListOfDevices[NwkId]["Ep"][Ep]["0201"]: + if self.ListOfDevices[NwkId]["Ep"][Ep]["0201"]["e011"] != {} and self.ListOfDevices[NwkId]["Ep"][Ep]["0201"]["e011"] != "": + _value_mode_hact = self.ListOfDevices[NwkId]["Ep"][Ep]["0201"]["e011"] + _mode_hact = ((int(_value_mode_hact, 16) - 0x80)) & 1 + if _mode_hact == 0: + self.log.logging("Widget", "Debug", "------> Disable FIP widget: %s" % (value), NwkId) + nValue = 0 + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) + + elif ClusterId == "fc40": # Legrand FIP + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif WidgetType == "ThermoMode_3" and Attribute_ == "001c": - # Mapping of values to nValue and sValue - mode_mapping = { - 0x00: (0, "Off"), - 0x01: (1, "10"), - 0x03: (2, "20") - } - + # 0x00: Off + # 0x01: Confort + # 0x03: No-Freeze if "ThermoMode_3" not in SWITCH_SELECTORS: - continue - - if int(value) in mode_mapping: - nValue, sValue = mode_mapping[int(value)] - self.log.logging("Widget", "Debug", f"------> Thermostat Mode 3 {value} {nValue}:{sValue}", NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + return + if int(value) == 0x00: + # Off # 00 + nValue = 0 + sValue = "Off" + elif int(value) == 0x01: + # Confort # 10 + nValue = 1 + sValue = "10" + elif int(value) == 0x03: + # No-Freeze # 20 + nValue = 2 + sValue = "20" else: - # Unknown value - self.log.logging("Widget", "Error", f"MajDomoDevice - Unknown value for {NWKID}/{Ep}, clusterID: {clusterID}, value: {value}, Attribute_: {Attribute_}", NWKID) - continue - + # Unknow + self.log.logging("Widget", "Error", "MajDomoDevice - Unknown value for %s/%s, ClusterId: %s, value: %s, Attribute_=%s," % (NwkId, Ep, ClusterId, value, Attribute_), NwkId) + return + self.log.logging("Widget", "Log", "------> Thermostat Mode 3 %s %s:%s" % (value, nValue, sValue), NwkId) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) + elif WidgetType == "ThermoMode_2" and Attribute_ == "001c": # Use by Tuya TRV if "ThermoMode_2" not in SWITCH_SELECTORS: - continue - - value_mapping = SWITCH_SELECTORS["ThermoMode_2"] - - if value in value_mapping: - nValue, sValue = value_mapping[value] - self.log.logging("Widget", "Debug", f"------> Thermostat Mode 2 {value} {nValue}:{sValue}", NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) - else: - self.log.logging("Widget", "Error", f"Unknown TermoMode2 value: {value}") - continue + return + if value not in SWITCH_SELECTORS["ThermoMode_2"]: + self.log.logging("Widget", "Error", "Unknown TermoMode2 value: %s" % value) + return + nValue = SWITCH_SELECTORS["ThermoMode_2"][value][0] + sValue = SWITCH_SELECTORS["ThermoMode_2"][value][1] + self.log.logging("Widget", "Debug", "------> Thermostat Mode 2 %s %s:%s" % (value, nValue, sValue), NwkId) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif WidgetType == "ThermoMode_4" and Attribute_ == "001c": # Use by Tuya TRV nValue = value sValue = '%02d' %( nValue * 10) - self.log.logging("Widget", "Debug", "------> Thermostat Mode 4 %s %s:%s" % (value, nValue, sValue), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> Thermostat Mode 4 %s %s:%s" % (value, nValue, sValue), NwkId) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif WidgetType in ("ThermoMode_5", "ThermoMode_6") and Attribute_ == "001c": # Use by Tuya TRV nValue = value sValue = '%02d' %( nValue * 10) - self.log.logging("Widget", "Debug", "------> Thermostat Mode 5 %s %s:%s" % (value, nValue, sValue), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> Thermostat Mode 5 %s %s:%s" % (value, nValue, sValue), NwkId) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif model_name == "TS0601-eTRV5" and WidgetType in ("ThermoMode_5",) and Attribute_ == "6501": if value == 0: - self.log.logging("Widget", "Debug", "------> Thermostat Mode 5 %s %s:%s" % (value, 0, '00'), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, '00', BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> Thermostat Mode 5 %s %s:%s" % (value, 0, '00'), NwkId) + UpdateDevice_v2(self, Devices, device_unit, 0, '00', BatteryLevel, SignalLevel) - elif WidgetType in ("ThermoMode", "ACMode") and Attribute_ == "001c": - self.log.logging("Widget", "Debug", f"------> Thermostat Mode {value} type: {type(value)}", NWKID) - - mode_mapping = { - "00": (0, "00"), # Off - "20": (1, "10"), # Cool - "30": (2, "20"), # Heat - "40": (3, "30"), # Dry - "50": (4, "40") # Fan - } - + elif WidgetType in ("ThermoMode", "ACMode", ) and Attribute_ == "001c": + # value seems to come as int or str. To be fixed + self.log.logging("Widget", "Debug", "------> Thermostat Mode %s type: %s" % (value, type(value)), NwkId) if value in THERMOSTAT_MODE_2_LEVEL: - nValue, sValue = mode_mapping[THERMOSTAT_MODE_2_LEVEL[value]] - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) - + if THERMOSTAT_MODE_2_LEVEL[value] == "00": # Off + UpdateDevice_v2(self, Devices, device_unit, 0, "00", BatteryLevel, SignalLevel) + elif THERMOSTAT_MODE_2_LEVEL[value] == "20": # Cool + UpdateDevice_v2(self, Devices, device_unit, 1, "10", BatteryLevel, SignalLevel) + elif THERMOSTAT_MODE_2_LEVEL[value] == "30": # Heat + UpdateDevice_v2(self, Devices, device_unit, 2, "20", BatteryLevel, SignalLevel) + elif THERMOSTAT_MODE_2_LEVEL[value] == "40": # Dry + UpdateDevice_v2(self, Devices, device_unit, 3, "30", BatteryLevel, SignalLevel) + elif THERMOSTAT_MODE_2_LEVEL[value] == "50": # Fan + UpdateDevice_v2(self, Devices, device_unit, 4, "40", BatteryLevel, SignalLevel) + elif WidgetType in ("CAC221ACMode", ) and Attribute_ == "001c": - self.log.logging("Widget", "Debug", f"------> Thermostat CAC221ACMode {value} type: {type(value)}", NWKID) - - mode_mapping = { - "00": (0, "00"), # Off - "10": (1, "10"), # Auto - "20": (2, "20"), # Cool - "30": (3, "30"), # Heat - "40": (4, "40"), # Dry - "50": (5, "50") # Fan - } - + self.log.logging("Widget", "Debug", "------> Thermostat CAC221ACMode %s type: %s" % (value, type(value)), NwkId) if value in THERMOSTAT_MODE_2_LEVEL: - nValue, sValue = mode_mapping[THERMOSTAT_MODE_2_LEVEL[value]] - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) - + if THERMOSTAT_MODE_2_LEVEL[value] == "00": # Off + UpdateDevice_v2(self, Devices, device_unit, 0, "00", BatteryLevel, SignalLevel) + elif THERMOSTAT_MODE_2_LEVEL[value] == "10": # Auto + UpdateDevice_v2(self, Devices, device_unit, 1, "10", BatteryLevel, SignalLevel) + elif THERMOSTAT_MODE_2_LEVEL[value] == "20": # Cool + UpdateDevice_v2(self, Devices, device_unit, 2, "20", BatteryLevel, SignalLevel) + elif THERMOSTAT_MODE_2_LEVEL[value] == "30": # Heat + UpdateDevice_v2(self, Devices, device_unit, 3, "30", BatteryLevel, SignalLevel) + elif THERMOSTAT_MODE_2_LEVEL[value] == "40": # Dry + UpdateDevice_v2(self, Devices, device_unit, 4, "40", BatteryLevel, SignalLevel) + elif THERMOSTAT_MODE_2_LEVEL[value] == "50": # Fan + UpdateDevice_v2(self, Devices, device_unit, 5, "50", BatteryLevel, SignalLevel) + if ClusterType == "PM25" and WidgetType == "PM25": nvalue = round(value, 0) svalue = "%s" % (nvalue,) - UpdateDevice_v2(self, Devices, DeviceUnit, nvalue, svalue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) if ClusterType == "PM25" and WidgetType == "SmokePPM": nvalue = int(value) svalue = "%s" % (nvalue,) - UpdateDevice_v2(self, Devices, DeviceUnit, nvalue, svalue, BatteryLevel, SignalLevel) - + UpdateDevice_v2(self, Devices, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) + if ClusterType == "Alarm" and WidgetType == "AirPurifierAlarm": + nValue = 0 sValue = "%s %% used" %( value, ) # This is Alarm for Air Purifier if value >= 100: @@ -775,218 +743,194 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col else: # Green nValue = 1 - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if Attribute_ == "0006" and ClusterType == "FanControl" and WidgetType == "AirPurifierMode": nValue = value sValue = "%s" %(10 * value,) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if Attribute_ == "0007" and ClusterType == "FanControl" and WidgetType == "FanSpeed": nValue = round(value, 1) sValue = str(nValue) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if ClusterType == "Temp" and WidgetType == "AirQuality" and Attribute_ == "0002": # eco2 for VOC_Sensor from Nexturn is provided via Temp cluster nvalue = round(value, 0) svalue = "%s" % (nvalue) - UpdateDevice_v2(self, Devices, DeviceUnit, nvalue, svalue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nvalue, svalue, BatteryLevel, SignalLevel) if ClusterType == "Temp" and WidgetType == "Voc" and Attribute_ == "0003": # voc for VOC_Sensor from Nexturn is provided via Temp cluster svalue = "%s" % (round(value, 1)) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, svalue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "Temp" and WidgetType == "CH2O" and Attribute_ == "0004": # ch2o for Tuya Smart Air fis provided via Temp cluster svalue = "%s" % (round(value, 2)) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, svalue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "Temp" and WidgetType == "CarbonDioxyde" and Attribute_ == "0005": # CarbonDioxyde for Tuya Smart Air provided via Temp cluster svalue = "%s" % (round(value, 1)) - UpdateDevice_v2(self, Devices, DeviceUnit, 0, svalue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, svalue, BatteryLevel, SignalLevel) if ClusterType == "Temp" and WidgetType in ("Temp", "Temp+Hum", "Temp+Hum+Baro") and Attribute_ == "": # temperature - if check_erratic_value(self, NWKID, "Temp", value, -50, 100): + + if check_erratic_value(self, NwkId, "Temp", value, -50, 100): # We got an erratic value, no update to Domoticz self.log.logging("Widget", "Debug", "%s Receive an erratic Temp: %s, WidgetType: >%s<" % ( - NWKID, value, WidgetType), NWKID) + NwkId, value, WidgetType), NwkId) return - self.log.logging("Widget", "Log", "------> %s %s %s Temp: %s, WidgetType: >%s<" % ( - NWKID, ClusterType, WidgetType, value, WidgetType), NWKID) - adjvalue = 0 - if self.domoticzdb_DeviceStatus: - try: - adjvalue = round(self.domoticzdb_DeviceStatus.retreiveAddjValue_temp(Devices[DeviceUnit].ID), 1) - except Exception as e: - self.log.logging("Widget", "Error", "Error while trying to get Adjusted Value for Temp %s %s %s %s" % ( - NWKID, value, WidgetType, e), NWKID) - - current_temp, current_humi, current_hum_stat, current_baro, current_baro_forecast = retrieve_data_from_current(self, Devices, device_id_ieee, DeviceUnit, "0;0;0;0;0") + self.log.logging("Widget", "Debug", "------> Temp: %s, WidgetType: >%s<" % (value, WidgetType), NwkId) + adjvalue = temp_adjustement_value(self, Devices, NwkId, device_id_ieee, device_unit) - self.log.logging("Widget", "Debug", f"------> Adj Value: {adjvalue} from: {value} to {value + adjvalue} [{current_temp}, {current_humi}, {current_hum_stat}, {current_baro}, {current_baro_forecast}]", NWKID) - - NewNvalue = 0 - NewSvalue = "" + current_temp, current_humi, current_hum_stat, current_baro, current_baro_forecast = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, "0;0;0;0;0") if WidgetType == "Temp": NewNvalue = round(value + adjvalue, 1) - NewSvalue = str(NewNvalue) + NewSvalue = str(round(value + adjvalue, 1)) + self.log.logging("Widget", "Debug", "------> Temp update: %s - %s" % (NewNvalue, NewSvalue)) + UpdateDevice_v2(self, Devices, device_unit, NewNvalue, NewSvalue, BatteryLevel, SignalLevel) elif WidgetType == "Temp+Hum": NewSvalue = f"{round(value + adjvalue, 1)};{current_humi};{current_hum_stat}" + self.log.logging("Widget", "Debug", "------> Temp+Hum update: %s" % (NewSvalue)) + UpdateDevice_v2(self, Devices, device_unit, 0, NewSvalue, BatteryLevel, SignalLevel) elif WidgetType == "Temp+Hum+Baro": NewSvalue = f"{round(value + adjvalue, 1)};{current_humi};{current_hum_stat};{current_baro};{current_baro_forecast}" + UpdateDevice_v2(self, Devices, device_unit, 0, NewSvalue, BatteryLevel, SignalLevel) - self.log.logging("Widget", "Debug", f"------> {WidgetType} update: {NewNvalue} - {NewSvalue}") - UpdateDevice_v2(self, Devices, DeviceUnit, NewNvalue, NewSvalue, BatteryLevel, SignalLevel) - - if ClusterType == "Humi" and WidgetType in ("Humi", "Temp+Hum", "Temp+Hum+Baro"): - - self.log.logging("Widget", "Log", "------> %s %s %s Humi: %s, WidgetType: >%s<" % ( - NWKID, ClusterType, WidgetType, value, WidgetType), NWKID) - - NewNvalue = 0 - NewSvalue = "" + if ClusterType == "Humi" and WidgetType in ("Humi", "Temp+Hum", "Temp+Hum+Baro"): # humidite + self.log.logging("Widget", "Debug", "------> Humi: %s, WidgetType: >%s<" % (value, WidgetType), NwkId) + # Humidity Status humi_status = calculate_humidity_status(value) - current_temp, current_humi, current_hum_stat, current_baro, current_baro_forecast = retrieve_data_from_current(self, Devices, device_id_ieee, DeviceUnit, "0;0;0;0;0") + current_temp, current_humi, current_hum_stat, current_baro, current_baro_forecast = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, "0;0;0;0;0") if WidgetType == "Humi": - NewNvalue = value - NewSvalue = str(humi_status) - self.log.logging("Widget", "Debug", f"------> Humi update: {NewNvalue} - {NewSvalue}") - UpdateDevice_v2(self, Devices, DeviceUnit, NewNvalue, NewSvalue, BatteryLevel, SignalLevel) + NewSvalue = "%s" % humi_status + self.log.logging("Widget", "Debug", "------> Humi update: %s - %s" % (value, NewSvalue)) + UpdateDevice_v2(self, Devices, device_unit, value, NewSvalue, BatteryLevel, SignalLevel) elif WidgetType == "Temp+Hum": NewSvalue = f"{current_temp};{value};{humi_status}" - self.log.logging("Widget", "Debug", f"------> Temp+Hum update: {NewNvalue} - {NewSvalue}") - UpdateDevice_v2(self, Devices, DeviceUnit, NewNvalue, NewSvalue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> Temp+Hum update: %s" % (NewSvalue)) + UpdateDevice_v2(self, Devices, device_unit, 0, NewSvalue, BatteryLevel, SignalLevel) elif WidgetType == "Temp+Hum+Baro": NewSvalue = f"{current_temp};{value};{humi_status};{current_baro};{current_baro_forecast}" - self.log.logging("Widget", "Debug", f"------> Temp+Hum+Baro update: {NewNvalue} - {NewSvalue}") - UpdateDevice_v2(self, Devices, DeviceUnit, NewNvalue, NewSvalue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, NewSvalue, BatteryLevel, SignalLevel) if ClusterType == "Baro" and WidgetType in ("Baro", "Temp+Hum+Baro"): - self.log.logging("Widget", "Log", "------> %s %s %s Baro: %s, WidgetType: >%s<" % ( - NWKID, ClusterType, WidgetType, value, WidgetType), NWKID) - - adjvalue = 0 - try: - if self.domoticzdb_DeviceStatus: - adjvalue = round(self.domoticzdb_DeviceStatus.retreiveAddjValue_baro(Devices[DeviceUnit].ID), 1) - except Exception as e: - self.log.logging("Widget", "Error", f"Error while trying to get Adjusted Value for Temp {NWKID} {value} {WidgetType} {e}", NWKID) - - baroValue = round(value + adjvalue, 1) - self.log.logging("Widget", "Debug", f"------> Adj Value: {adjvalue} from: {value} to {baroValue}", NWKID) - - NewNvalue = 0 - NewSvalue = "" + self.log.logging("Widget", "Debug", "------> Baro: %s, WidgetType: %s" % (value, WidgetType), NwkId) + + adjvalue = baro_adjustement_value(self, Devices, NwkId, device_id_ieee, device_unit) + + baroValue = round((value + adjvalue), 1) + self.log.logging("Widget", "Debug", "------> Adj Value : %s from: %s to %s " % (adjvalue, value, baroValue), NwkId) Bar_forecast = calculate_baro_forecast(baroValue) - current_temp, current_humi, current_hum_stat, current_baro, current_baro_forecast = retrieve_data_from_current(self, Devices, device_id_ieee, DeviceUnit, "0;0;0;0;0") - + current_temp, current_humi, current_hum_stat, current_baro, current_baro_forecast = retrieve_data_from_current(self, Devices, device_id_ieee, device_unit, "0;0;0;0;0") + if WidgetType == "Baro": NewSvalue = f"{baroValue};{Bar_forecast}" + UpdateDevice_v2(self, Devices, device_unit, 0, NewSvalue, BatteryLevel, SignalLevel) + elif WidgetType == "Temp+Hum+Baro": NewSvalue = f"{current_temp};{current_humi};{current_hum_stat};{baroValue};{Bar_forecast}" - - UpdateDevice_v2(self, Devices, DeviceUnit, NewNvalue, NewSvalue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, NewSvalue, BatteryLevel, SignalLevel) if "BSO-Orientation" in ClusterType and WidgetType == "BSO-Orientation": - angle = int(value, 16) - nValue = min(10, round(angle / 10) + 1) + nValue = 1 + (round(int(value, 16) / 10)) + if nValue > 10: + nValue = 10 + sValue = str(nValue * 10) - self.log.logging("Widget", "Debug", f"BSO-Orientation Angle: 0x{value}/{angle} Converted into nValue: {nValue} sValue: {sValue}") - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", " BSO-Orientation Angle: 0x%s/%s Converted into nValue: %s sValue: %s" % (value, int(value, 16), nValue, sValue)) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) + return if ClusterType == "Switch" and WidgetType == "SwitchAlarm": if isinstance(value, str): nValue = int(value, 16) else: self.log.logging("Widget", "Error", "Looks like this value is not provided in str for %s/%s %s %s %s %s %s" %( - NWKID, Ep, model_name, clusterID, ClusterType, WidgetType, value)) + NwkId, Ep, model_name, ClusterId, ClusterType, WidgetType, value)) nValue = value sValue = "%02x" %nValue - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if ClusterType == "TamperSwitch" and WidgetType == "SwitchAlarm": nValue = value sValue = "%02x" %nValue - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if "Notification" in ClusterType and WidgetType == "Notification": # Notification # value is a str containing all Orientation information to be updated on Text Widget nValue = 0 sValue = value - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - - + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + if ClusterType in ( "Motion", "Door",) and WidgetType == "Motion": - self.log.logging("Widget", "Debug", "------> Motion %s" % (value), NWKID) + self.log.logging("Widget", "Debug", "------> Motion %s" % (value), NwkId) if isinstance(value, str): nValue = int(value, 16) else: self.log.logging("Widget", "Error", "Looks like this value is not provided in str for %s/%s %s %s %s %s %s" %( - NWKID, Ep, model_name, clusterID, ClusterType, WidgetType, value)) + NwkId, Ep, model_name, ClusterId, ClusterType, WidgetType, value)) nValue = value if nValue == 1: - UpdateDevice_v2(self, Devices, DeviceUnit, 1, "On", BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, 1, "On", BatteryLevel, SignalLevel, ForceUpdate_=True) else: - UpdateDevice_v2(self, Devices, DeviceUnit, 0, "Off", BatteryLevel, SignalLevel, ForceUpdate_=False) - continue - - excluded_widget_types = { - "ThermoModeEHZBRTS", "HeatingSwitch", "HeatingStatus", "ThermoMode_2", "ThermoMode_3", "ThermoSetpoint", - "ThermoOnOff", "Motionac01" - } - - allowed_conditions = { - (ClusterType in ("IAS_ACE", "Door", "Switch", "SwitchButton", "AqaraOppleMiddle", "Ikea_Round_5b", "Ikea_Round_OnOff", - "Vibration", "OrviboRemoteSquare", "Button_3", "LumiLock") and WidgetType not in excluded_widget_types), - (ClusterType == WidgetType == "DoorLock"), - (ClusterType == WidgetType == "Alarm"), - (ClusterType == "Alarm" and WidgetType == "Tamper"), - (ClusterType == "DoorLock" and WidgetType == "Vibration"), - (ClusterType == "FanControl" and WidgetType == "FanControl"), - ("ThermoMode" in ClusterType and WidgetType == "ACMode_2"), - ("ThermoMode" in ClusterType and WidgetType == "ACSwing" and Attribute_ == "fd00"), - ("ThermoMode" in ClusterType and WidgetType == "ThermoMode_7" and Attribute_ == "001c"), - (WidgetType == "KF204Switch" and ClusterType in ("Switch", "Door")), - (WidgetType == "Valve" and Attribute_ == "0014"), - ("ThermoMode" in ClusterType and WidgetType == "ThermoOnOff"), - ("Heiman" in ClusterType and WidgetType == "HeimanSceneSwitch") - } + UpdateDevice_v2(self, Devices, device_unit, 0, "Off", BatteryLevel, SignalLevel, ForceUpdate_=False) + return - if any(allowed_condition for allowed_condition in allowed_conditions): + if ( + WidgetType not in ("ThermoModeEHZBRTS", "HeatingSwitch", "HeatingStatus", "ThermoMode_2", "ThermoMode_3", "ThermoSetpoint", "ThermoOnOff", "Motionac01") + and ( + ClusterType in ( "IAS_ACE", "Door", "Switch", "SwitchButton", "AqaraOppleMiddle", "Ikea_Round_5b", "Ikea_Round_OnOff", "Vibration", "OrviboRemoteSquare", "Button_3", "LumiLock", ) + or (ClusterType == WidgetType == "DoorLock") + or (ClusterType == WidgetType == "Alarm") + or (ClusterType == "Alarm" and WidgetType == "Tamper") + or (ClusterType == "DoorLock" and WidgetType == "Vibration") + or (ClusterType == "FanControl" and WidgetType == "FanControl") + or ("ThermoMode" in ClusterType and WidgetType == "ACMode_2") + or ("ThermoMode" in ClusterType and WidgetType == "ACSwing" and Attribute_ == "fd00") + or ("ThermoMode" in ClusterType and WidgetType == "ThermoMode_7" and Attribute_ == "001c") + or (WidgetType == "KF204Switch" and ClusterType in ("Switch", "Door")) + or (WidgetType == "Valve" and Attribute_ == "0014") + or ("ThermoMode" in ClusterType and WidgetType == "ThermoOnOff") + or ("Heiman" in ClusterType and WidgetType == "HeimanSceneSwitch") + ) + ): # Plug, Door, Switch, Button ... # We reach this point because ClusterType is Door or Switch. It means that Cluster 0x0006 or 0x0500 # So we might also have to manage case where we receive a On or Off for a LvlControl WidgetType like a dimming Bulb. self.log.logging( "Widget", "Debug", "------> Generic Widget for %s ClusterType: %s WidgetType: %s Value: %s" % ( - NWKID, ClusterType, WidgetType, value), NWKID, ) + NwkId, ClusterType, WidgetType, value), NwkId, ) if ClusterType == "Switch" and WidgetType == "LvlControl": - # Called with ClusterID: 0x0006 but we have to update a Dimmer, so we need to keep the level - nValue = prev_nValue + # Called with ClusterId: 0x0006 but we have to update a Dimmer, so we need to keep the level + nValue = int(value) sValue = prev_sValue if switchType in (13, 16): # Correct for Blinds where we have to display % if value == "00": - nValue, sValue = 0, "0" - elif value == "01" and sValue == "100": - nValue, sValue = 1, "100" + nValue = 0 + sValue = "0" + elif value == "01" and prev_sValue == "100": + nValue = 1 + sValue = "100" else: nValue = 2 - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif ClusterType == "Switch" and WidgetType == "Alarm": pass @@ -997,7 +941,7 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col sValue = "Off" else: sValue = "On" - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif WidgetType == "DSwitch": # double switch avec EP different @@ -1006,17 +950,17 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col if Ep == "01": nValue = 1 sValue = "10" - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif Ep == "02": nValue = 2 sValue = "20" - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif Ep == "03": nValue = 3 sValue = "30" - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif (WidgetType == "TuyaSirenHumi" and Attribute_ != "0172") or (WidgetType == "TuyaSirenTemp" and Attribute_ != "0171") or (WidgetType == "TuyaSiren" and Attribute_ != "0168"): return @@ -1027,7 +971,7 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col sValue = "Off" else: sValue = "On" - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=False) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=False) elif WidgetType == "DButton": # double bouttons avec EP different lumi.sensor_86sw2 @@ -1036,17 +980,17 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col if Ep == "01": nValue = 1 sValue = "10" - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) elif Ep == "02": nValue = 2 sValue = "20" - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) elif Ep == "03": nValue = 3 sValue = "30" - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) elif WidgetType == "DButton_3": # double bouttons avec EP different lumi.sensor_86sw2 @@ -1066,7 +1010,7 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col state = "30" data = "03" - UpdateDevice_v2(self, Devices, DeviceUnit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) elif Ep == "02": if _value == 1: @@ -1081,7 +1025,7 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col state = "60" data = "06" - UpdateDevice_v2(self, Devices, DeviceUnit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) elif Ep == "03": if _value == 1: @@ -1096,32 +1040,31 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col state = "90" data = "09" - UpdateDevice_v2(self, Devices, DeviceUnit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) + UpdateDevice_v2(self, Devices, device_unit, int(data), str(state), BatteryLevel, SignalLevel, ForceUpdate_=True) elif WidgetType == "LvlControl" or WidgetType in ( "ColorControlRGB", "ColorControlWW", "ColorControlRGBWW", "ColorControlFull", "ColorControl", ): - if switchType in (13, 14, 15, 16): # Required Numeric value if value == "00": - UpdateDevice_v2(self, Devices, DeviceUnit, 0, "0", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, "0", BatteryLevel, SignalLevel) else: # We are in the case of a Shutter/Blind inverse. If we receieve a Read Attribute telling it is On, great # We only update if the shutter was off before, otherwise we will keep its Level. if prev_nValue == 0 and prev_sValue == "Off": - UpdateDevice_v2(self, Devices, DeviceUnit, 1, "100", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 1, "100", BatteryLevel, SignalLevel) else: # Required Off and On if value == "00": - UpdateDevice_v2(self, Devices, DeviceUnit, 0, "Off", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, "Off", BatteryLevel, SignalLevel) else: if prev_sValue == "Off": # We do update only if this is a On/off - UpdateDevice_v2(self, Devices, DeviceUnit, 1, "On", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 1, "On", BatteryLevel, SignalLevel) - elif WidgetType == "VenetianInverted" and model_name in ( "PR412", "CPR412", "CPR412-E") and clusterID == "0006": - self.log.logging( "Widget", "Debug", "--++-> %s/%s ClusterType: %s Updating %s Value: %s" % (NWKID, Ep, ClusterType, WidgetType, value), NWKID, ) + elif WidgetType == "VenetianInverted" and model_name in ( "PR412", "CPR412", "CPR412-E") and ClusterId == "0006": + self.log.logging( "Widget", "Debug", "--++-> %s/%s ClusterType: %s Updating %s Value: %s" % (NwkId, Ep, ClusterType, WidgetType, value), NwkId, ) # nValue will depends if we are on % or not if value == '01': nValue = 0 @@ -1135,338 +1078,378 @@ def MajDomoDevice(self, Devices, NWKID, Ep, clusterID, value, Attribute_="", Col nValue = 17 sValue = "0" - self.log.logging("Widget", "Debug", "------> %s %s/%s Value: %s:%s" % (WidgetType, NWKID, Ep, nValue, sValue), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) + self.log.logging("Widget", "Debug", "------> %s %s/%s Value: %s:%s" % (WidgetType, NwkId, Ep, nValue, sValue), NwkId) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) elif WidgetType in ("VenetianInverted", "Venetian", "WindowCovering", "VanneInverted", "Vanne", "Curtain", "CurtainInverted"): _value = int(value, 16) - self.log.logging( "Widget", "Debug", "------> %s/%s ClusterType: %s Updating %s Value: %s" % (NWKID, Ep, ClusterType, WidgetType, _value), NWKID, ) + self.log.logging( "Widget", "Debug", "------> %s/%s ClusterType: %s Updating %s Value: %s" % (NwkId, Ep, ClusterType, WidgetType, _value), NwkId, ) if WidgetType in ("VenetianInverted", "VanneInverted"): _value = 100 - _value - self.log.logging("Widget", "Debug", "------> Patching %s/%s Value: %s" % (NWKID, Ep, _value), NWKID) + self.log.logging("Widget", "Debug", "------> Patching %s/%s Value: %s" % (NwkId, Ep, _value), NwkId) # nValue will depends if we are on % or not if _value == 0: nValue = 0 elif _value == 100: nValue = 1 else: - nValue = 17 if switchType in (4, 15) else 2 - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, str(_value), BatteryLevel, SignalLevel) + if switchType in (4, 15): + nValue = 17 + else: + nValue = 2 + UpdateDevice_v2(self, Devices, device_unit, nValue, str(_value), BatteryLevel, SignalLevel) elif ( - ( - (ClusterType == "FanControl" and WidgetType == "FanControl") - or ("ThermoMode" in ClusterType and WidgetType == "ACSwing" and Attribute_ == "fd00") - ) + ((ClusterType == "FanControl" and WidgetType == "FanControl") or ("ThermoMode" in ClusterType and WidgetType == "ACSwing" and Attribute_ == "fd00")) and model_name in ("AC211", "AC221", "CAC221") - and "Ep" in self.ListOfDevices[NWKID] - and WidgetEp in self.ListOfDevices[NWKID]["Ep"] - and "0201" in self.ListOfDevices[NWKID]["Ep"][WidgetEp] - and "001c" in self.ListOfDevices[NWKID]["Ep"][WidgetEp]["0201"] - and self.ListOfDevices[NWKID]["Ep"][WidgetEp]["0201"]["001c"] == 0x00 + and "Ep" in self.ListOfDevices[NwkId] + and WidgetEp in self.ListOfDevices[NwkId]["Ep"] + and "0201" in self.ListOfDevices[NwkId]["Ep"][WidgetEp] + and "001c" in self.ListOfDevices[NwkId]["Ep"][WidgetEp]["0201"] + and self.ListOfDevices[NwkId]["Ep"][WidgetEp]["0201"]["001c"] == 0x00 ): # Thermo mode is Off, let's switch off Wing and Fan self.log.logging("Widget", "Debug", "------> Switch off as System Mode is Off") - UpdateDevice_v2(self, Devices, DeviceUnit, 0, "00", BatteryLevel, SignalLevel) + UpdateDevice_v2(self, Devices, device_unit, 0, "00", BatteryLevel, SignalLevel) else: if WidgetType in SWITCH_SELECTORS and value in SWITCH_SELECTORS[WidgetType]: self.log.logging("Widget", "Debug", "------> Auto Update %s" % str(SWITCH_SELECTORS[WidgetType][value])) - if len(SWITCH_SELECTORS[WidgetType][value]) == 2: - nValue, sValue = SWITCH_SELECTORS[WidgetType][value] + + selector_values = SWITCH_SELECTORS[WidgetType][value] + + if len(selector_values) == 2: + nValue, sValue = selector_values _ForceUpdate = SWITCH_SELECTORS[WidgetType]["ForceUpdate"] - self.log.logging( "Widget", "Debug", "------> Switch update WidgetType: %s with %s" % ( - WidgetType, str(SWITCH_SELECTORS[WidgetType])), NWKID, ) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=_ForceUpdate) + + self.log.logging("Widget", "Debug", f"------> Switch update WidgetType: {WidgetType} with {str(SWITCH_SELECTORS[WidgetType])}", NwkId) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=_ForceUpdate) else: - self.log.logging( "Widget", "Error", "------> len(SWITCH_SELECTORS[ %s ][ %s ]) == %s" % ( - WidgetType, value, len(SWITCH_SELECTORS[WidgetType])), NWKID, ) + self.log.logging("Widget", "Error", f"------> len(SWITCH_SELECTORS[{WidgetType}][{value}]) == {len(selector_values)}", NwkId) else: - self.log.logging("Widget", "Error", "------> Auto Update (%s %s) not found in SWITCH_SELECTORS" % ( WidgetType, value)) + self.log.logging("Widget", "Log", f"------> Auto Update requested for NwkId: {NwkId} {ClusterType} {WidgetType} {value} not found in SWITCH_SELECTORS") - if "WindowCovering" in ClusterType: # 0x0102 - if WidgetType in ("VenetianInverted", "Venetian", "Vanne", "VanneInverted", "WindowCovering", "Curtain", "CurtainInverted", "Blind"): - _value = int(value, 16) - self.log.logging( - "Widget", - "Debug", - "------> %s/%s ClusterType: %s Updating %s Value: %s" % (NWKID, Ep, ClusterType, WidgetType, _value), - NWKID, - ) - if WidgetType in ("VenetianInverted", "VanneInverted", "CurtainInverted"): - _value = 100 - _value - self.log.logging("Widget", "Debug", "------> Patching %s/%s Value: %s" % (NWKID, Ep, _value), NWKID) - # nValue will depends if we are on % or not - if _value == 0: - nValue = 0 - elif _value == 100: - nValue = 1 - else: - nValue = 17 if switchType in (4, 15) else 2 - self.log.logging("Widget", "Debug", "------> %s %s/%s Value: %s:%s" % (WidgetType, NWKID, Ep, nValue, _value), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, str(_value), BatteryLevel, SignalLevel) + + if "WindowCovering" in ClusterType and WidgetType in ("VenetianInverted", "Venetian", "Vanne", "VanneInverted", "WindowCovering", "Curtain", "CurtainInverted", "Blind"): + nValue, sValue = _domo_convert_windows_covering( self, value, Devices, device_id_ieee, device_unit, NwkId, WidgetType ) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel) if "LvlControl" in ClusterType: # LvlControl ( 0x0008) - if WidgetType == "LvlControl" or ( WidgetType in ( "BSO-Volet", "Blind", ) ): - - self.log.logging("Widget", "Debug", "------> LvlControl analogValue: -> %s" % value, NWKID) - normalized_value = normalized_lvl_value(self, Devices, device_id_ieee, DeviceUnit, value) - self.log.logging("Widget", "Debug", "------> LvlControl new sValue: -> %s old nValue/sValue %s:%s" % ( - normalized_value, prev_nValue, prev_sValue), NWKID) - - # In case we reach 0% or 100%, we shouldn't switch Off or On, except in the case of Shutter/Blind - if normalized_value == 0 or normalized_value == 100: - nValue = 0 if normalized_value == 0 else 1 - if switchType: - self.log.logging("Widget", "Debug", "------> LvlControl UpdateDevice: -> %s/%s SwitchType: %s" % ( - nValue, normalized_value, switchType), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, str(normalized_value), BatteryLevel, SignalLevel) - else: - if prev_nValue == 0 and (prev_sValue == "Off" or prev_sValue == str(normalized_value)): - pass - else: - self.log.logging("Widget", "Debug", "------> LvlControl UpdateDevice: -> %s/%s" % (nValue, normalized_value), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, str(normalized_value), BatteryLevel, SignalLevel) - else: - if prev_nValue == 0 and (prev_sValue == "Off" or prev_sValue == str(normalized_value)): - pass - elif switchType in (13, 14, 15, 16): - self.log.logging("Widget", "Debug", "------> LvlControl UpdateDevice: -> %s/%s SwitchType: %s" % ( - 2, normalized_value, switchType), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, 2, str(normalized_value), BatteryLevel, SignalLevel) - else: - # Just update the Level if Needed - self.log.logging("Widget", "Debug", "------> LvlControl UpdateDevice: -> %s/%s SwitchType: %s" % ( - prev_nValue, normalized_value, switchType), NWKID) - UpdateDevice_v2(self, Devices, DeviceUnit, prev_nValue, str(normalized_value), BatteryLevel, SignalLevel) + tuple_value = _domo_convert_level_control( self, Devices, device_id_ieee, device_unit, value, NwkId, switchType, WidgetType, prev_nValue, prev_sValue) + if tuple_value : + UpdateDevice_v2(self, Devices, device_unit, tuple_value[0], tuple_value[1], BatteryLevel, SignalLevel) + + if ClusterType in ( "ColorControlRGB", "ColorControlWW", "ColorControlRGBWW", "ColorControlFull", "ColorControl", ) and ClusterType == WidgetType: + # We just manage the update of the Dimmer (Control Level) + nValue, sValue = _domo_convert_colorcontrol( self, value ) + UpdateDevice_v2(self, Devices, device_unit, nValue, str(sValue), BatteryLevel, SignalLevel, Color_) + + if "Orientation" in ClusterType and WidgetType == "Orientation": + # Xiaomi Vibration + # value is a str containing all Orientation information to be updated on Text Widget + nValue, sValue = _domo_convert_orientation( value) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + if "Strenght" in ClusterType and WidgetType == "Strenght": + # value is a str containing all Orientation information to be updated on Text Widget + nValue, sValue = _domo_convert_strenght( value) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + if "Distance" in ClusterType and WidgetType == "Distance": + # value is a str containing all Distance information in cm + nValue, sValue = _domo_convert_distance( value ) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + if "Lux" in ClusterType and WidgetType == "Lux": + nValue, sValue = _domo_convert_lux( value) + UpdateDevice_v2(self, Devices, device_unit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=False) - elif WidgetType in ( "ColorControlRGB", "ColorControlWW", "ColorControlRGBWW", "ColorControlFull", "ColorControl", ): - if prev_nValue != 0 or prev_sValue != "Off": - nValue, sValue = getDimmerLevelOfColor(self, value) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, str(sValue), BatteryLevel, SignalLevel, Color_) + # Check if this Device belongs to a Group. In that case update group + CheckUpdateGroup(self, NwkId, Ep, ClusterId) - elif WidgetType == "LegrandSelector": - self.log.logging("Widget", "Debug", "------> LegrandSelector : Value -> %s" % value, NWKID) - if value == "00": - nValue = 0 - sValue = "00" # Off - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - elif value == "01": - nValue = 1 - sValue = "10" # On - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - elif value == "moveup": - nValue = 2 - sValue = "20" # Move Up - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - elif value == "movedown": - nValue = 3 - sValue = "30" # Move Down - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - elif value == "stop": - nValue = 4 - sValue = "40" # Stop - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - else: - self.log.logging("Widget", "Error", "------> %s LegrandSelector Unknown value %s" % (NWKID, value)) - - elif WidgetType == "LegrandSleepWakeupSelector": - self.log.logging("Widget", "Debug", "------> LegrandSleepWakeupSelector : Value -> %s" % value, NWKID) - if value == "00": - nValue = 1 - sValue = "10" # sleep - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - elif value == "01": - nValue = 2 - sValue = "20" # wakeup - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - else: - self.log.logging("Widget", "Error", "------> %s LegrandSleepWakeupSelector Unknown value %s" % (NWKID, value)) +# Helpers - elif WidgetType == "Generic_5_buttons": - self.log.logging("Widget", "Debug", "------> Generic 5 buttons : Value -> %s" % value, NWKID) - nvalue = 0 - state = "00" - if value == "00": - nvalue = 0 - sValue = "00" - elif value == "01": - nvalue = 1 - sValue = "10" +def _domo_convert_windows_covering( self, value, Devices, DeviceId, Unit, NwkId, WidgetType ): - elif value == "02": - nvalue = 2 - sValue = "20" + dimm_blind_nvalue = is_dimmable_blind(self, Devices, DeviceId, Unit) + value = int(value, 16) + + if WidgetType in ("VenetianInverted", "VanneInverted", "CurtainInverted"): + value = 100 - value + + # nValue will depends if we are on % or not + if value == 0: + nValue = 0 + elif value == 100: + nValue = 1 + else: + nValue = dimm_blind_nvalue if dimm_blind_nvalue else 2 + + self.log.logging("Widget", "Debug", "------> %s %s Value: %s:%s" % (WidgetType, NwkId, nValue, value), NwkId) + return nValue, str(value) - elif value == "03": - nvalue = 3 - sValue = "30" - elif value == "04": - nvalue = 4 - sValue = "40" - else: - return +def _domo_convert_colorcontrol( self, value ): + return getDimmerLevelOfColor(self, value) - UpdateDevice_v2(self, Devices, DeviceUnit, nvalue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - - elif WidgetType == "GenericLvlControl": - # 1,10: Off - # 2,20: On - # 3,30: Move Up - # 4,40: Move Down - # 5,50: Stop - self.log.logging("Widget", "Debug", "------> GenericLvlControl : Value -> %s" % value, NWKID) - if value == "off": - nvalue = 1 - sValue = "10" # Off - - elif value == "on": - nvalue = 2 - sValue = "20" # On - - elif value == "moveup": - nvalue = 3 - sValue = "30" # Move Up - - elif value == "movedown": - nvalue = 4 - sValue = "40" # Move Down - - elif value == "stop": - nvalue = 5 - sValue = "50" # Stop - else: - return + +def _domo_convert_strenght( value ): + return 0, value - UpdateDevice_v2(self, Devices, DeviceUnit, nvalue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) - elif WidgetType == "HueSmartButton": - self.log.logging("Widget", "Debug", "------> HueSmartButton : Value -> %s" % value, NWKID) - if value == "toggle": - nvalue = 1 - sValue = "10" # toggle - elif value == "move": - nvalue = 2 - sValue = "20" # Move - else: - return - UpdateDevice_v2(self, Devices, DeviceUnit, nvalue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) +def _domo_convert_orientation( value ): + return 0, value - elif WidgetType == "INNR_RC110_SCENE": - self.log.logging("Widget", "Debug", "------> Updating INNR_RC110_SCENE (LvlControl) Value: %s" % value, NWKID) - if value == "Off": - nValue = 0 - elif value == "On": - nValue = 1 +def _domo_convert_distance( value ): + return 0, value - elif value == "clickup": - nValue = 2 - elif value == "clickdown": - nValue = 3 +def _domo_convert_lux( value): + return int(value), value - elif value == "moveup": - nValue = 4 - elif value == "movedown": - nValue = 5 +def _domo_convert_level_control( self, Devices, DeviceId, Unit, value, NwkId, switchType, WidgetType, prev_nValue, prev_sValue): + if WidgetType == "LvlControl" or ( WidgetType in ( "BSO-Volet", "Blind", ) ): + # We need to handle the case, where we get an update from a Read Attribute or a Reporting message + # We might get a Level, but the device is still Off and we shouldn't make it On . + self.log.logging("Widget", "Debug", "_domo_convert_level_control input value: -> %s" % value, NwkId) + + normalized_value = normalized_lvl_value( switchType, value ) + self.log.logging( "Widget", "Debug", "_domo_convert_level_control normalized Value: -> %s previous nValue/sValue %s:%s" % ( + normalized_value, prev_nValue, prev_sValue), NwkId, ) + + dimm_blind_nvalue = is_dimmable_blind(self, Devices, DeviceId, Unit) + self.log.logging( "Widget", "Debug", "_domo_convert_level_control dimm_blind_value %s" % (dimm_blind_nvalue), NwkId, ) + + # In case we reach 0% or 100% we shouldn't switch Off or On, except in the case of Shutter/Blind + if normalized_value == 0: + return handle_normalized_value_off(self, dimm_blind_nvalue, switchType, prev_nValue, prev_sValue, normalized_value, NwkId) - elif value == "stop": - nValue = 6 + if normalized_value == 100: + return handle_normalized_value_on(self, dimm_blind_nvalue, switchType, prev_nValue, prev_sValue, normalized_value, NwkId) - elif value == "scene1": - nValue = 7 + # sValue != 0 and sValue != 100 + return handle_normalized_other(self, dimm_blind_nvalue, prev_nValue, prev_sValue, normalized_value, switchType, NwkId) - elif value == "scene2": - nValue = 8 + elif WidgetType in ( "ColorControlRGB", "ColorControlWW", "ColorControlRGBWW", "ColorControlFull", "ColorControl", ): + if prev_nValue != 0 or prev_sValue != "Off": + nValue, sValue = getDimmerLevelOfColor(self, value) + return nValue, str(sValue) + + elif WidgetType == "LegrandSelector": + self.log.logging("Widget", "Debug", "------> LegrandSelector : Value -> %s" % value, NwkId) + _value_mapping = { + "00": (0, "00"), + "01": (1, "10"), + "moveup": (2, "20"), + "movedown": (3, "30"), + "stop": (4, "40"), + } + return _value_mapping.get(value) - elif value == "scene3": - nValue = 9 + elif WidgetType == "LegrandSleepWakeupSelector": + self.log.logging("Widget", "Debug", "------> LegrandSleepWakeupSelector : Value -> %s" % value, NwkId) + _value_mapping = { + "00": (1, "10"), + "01": (2, "20"), + } + return _value_mapping.get(value) + + elif WidgetType == "Generic_5_buttons": + self.log.logging("Widget", "Debug", "------> Generic 5 buttons : Value -> %s" % value, NwkId) + _value_mapping = { + "00": (0, "00"), + "01": (1, "10"), + "02": (2, "20"), + "03": (3, "30"), + "04": (4, "40"), + } + return _value_mapping.get(value) + + elif WidgetType == "GenericLvlControl": + self.log.logging("Widget", "Debug", "------> GenericLvlControl : Value -> %s" % value, NwkId) + _value_mapping = { + "off": (1, "10"), # Off + "on": (2, "20"), # On + "moveup": (3, "30"), # Move Up + "movedown": (4, "40"), # Move Down + "stop": (5, "50"), # Stop + } + return _value_mapping.get(value) - elif value == "scene4": - nValue = 10 + elif WidgetType == "HueSmartButton": + self.log.logging("Widget", "Debug", "------> HueSmartButton : Value -> %s" % value, NwkId) + _value_mapping = { + "toggle": (1, "10"), # toggle + "move": (2, "20"), # Move + } + return _value_mapping.get(value) + + elif WidgetType == "INNR_RC110_SCENE": + self.log.logging("Widget", "Debug", "------> Updating INNR_RC110_SCENE (LvlControl) Value: %s" % value, NwkId) + _value_mapping = { + "Off": 0, + "On": 1, + "clickup": 2, + "clickdown": 3, + "moveup": 4, + "movedown": 5, + "stop": 6, + "scene1": 7, + "scene2": 8, + "scene3": 9, + "scene4": 10, + "scene5": 11, + "scene6": 12, + } + + nValue = _value_mapping.get(value) + if nValue is None: + return None + sValue = "%s" % (10 * nValue) + return nValue, sValue + + elif WidgetType == "INNR_RC110_LIGHT": + self.log.logging("Widget", "Debug", "------> Updating INNR_RC110_LIGHT (LvlControl) Value: %s" % value, NwkId) + _value_mapping = { + "00": 0, + "01": 1, + "clickup": 2, + "clickdown": 3, + "moveup": 4, + "movedown": 5, + "stop": 6, + } + nValue = _value_mapping.get(value) + if nValue is None: + return None + sValue = "%s" % (10 * nValue) + return nValue, sValue - elif value == "scene5": - nValue = 11 + elif WidgetType == "TINT_REMOTE_WHITE": + nValue = int(value) + sValue = "%s" % (10 * nValue) + return nValue, sValue - elif value == "scene6": - nValue = 12 - else: - return + return None - sValue = "%s" % (10 * nValue) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) - elif WidgetType == "INNR_RC110_LIGHT": - self.log.logging("Widget", "Debug", "------> Updating INNR_RC110_LIGHT (LvlControl) Value: %s" % value, NWKID) - if value == "00": - nValue = 0 +def handle_normalized_value_off(self, dimm_blind_nvalue, switchType, prev_nValue, prev_sValue, normalized_value, NwkId): - elif value == "01": - nValue = 1 + if dimm_blind_nvalue: + # Blind, update Switch Closed + self.log.logging("Widget", "Debug", "handle_normalized_value_off -> %s/%s SwitchType: %s" % (0, 0, switchType), NwkId) + return 0, "0" + + if prev_nValue == 0 and (prev_sValue == "Off" or prev_sValue == str(normalized_value)): + # It is not a blind and it is already Off, do nothing + return None - elif value == "clickup": - nValue = 2 + # All other cases we Switch Off + self.log.logging("Widget", "Debug", "handle_normalized_value_off -> %s/%s" % (0, 0), NwkId) + return 0, "0" - elif value == "clickdown": - nValue = 3 - elif value == "moveup": - nValue = 4 +def handle_normalized_value_on(self, dimm_blind_nvalue, switchType, prev_nValue, prev_sValue, normalized_value, NwkId): + if dimm_blind_nvalue: + # Blind, update Switch Open + self.log.logging("Widget", "Debug", "handle_normalized_value_on -> %s/%s SwitchType: %s" % (1, 100, switchType), NwkId) + return 1, "100" + + if prev_nValue == 0 and (prev_sValue == "Off" or prev_sValue == str(normalized_value)): + # It is not a blind and it is already Off, do nothing + return None - elif value == "movedown": - nValue = 5 + # All other cases we Switch Off + self.log.logging("Widget", "Debug", "handle_normalized_value_on -> %s/%s" % (1, 100), NwkId) + return 1, "100" - elif value == "stop": - nValue = 6 - else: - return - sValue = "%s" % (10 * nValue) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) +def handle_normalized_other(self, dimm_blind_nvalue, prev_nValue, prev_sValue, normalized_value, switchType, NwkId): + if dimm_blind_nvalue: + self.log.logging("Widget", "Debug", "handle_normalized_other -> %s SwitchType: %s dimm_blind_value: %s" % ( + normalized_value, switchType, dimm_blind_nvalue), NwkId) + return dimm_blind_nvalue, str(normalized_value) + + if prev_nValue == 0 and (prev_sValue == "Off" or prev_sValue == str(normalized_value)): + # Do nothing. We receive a ReadAttribute giving the position of an Off device. + return None + + # Just update the Level if Needed + self.log.logging("Widget", "Debug", "handle_normalized_other -> %s SwitchType: %s prev value: %s" % (normalized_value, switchType, prev_nValue ), NwkId) + return prev_nValue, str(normalized_value) - elif WidgetType == "TINT_REMOTE_WHITE": - nValue = int(value) - sValue = "%s" % (10 * nValue) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel) - if ClusterType in ( "ColorControlRGB", "ColorControlWW", "ColorControlRGBWW", "ColorControlFull", "ColorControl", ) and ClusterType == WidgetType: - # We just manage the update of the Dimmer (Control Level) - nValue, sValue = getDimmerLevelOfColor(self, value) - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, str(sValue), BatteryLevel, SignalLevel, Color_) +def is_time_to_domo_update(self, NwkId, Ep): - if "Orientation" in ClusterType and WidgetType == "Orientation": - # Xiaomi Vibration - # value is a str containing all Orientation information to be updated on Text Widget - nValue = 0 - sValue = value - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + if self.CommiSSionning and NwkId not in self.ListOfDevices: + return False - if "Strenght" in ClusterType and WidgetType == "Strenght": - # value is a str containing all Orientation information to be updated on Text Widget - nValue = 0 - sValue = value - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + if NwkId not in self.ListOfDevices: + self.log.logging("Widget", "Error", "MajDomoDevice - %s not known" % NwkId, NwkId) + zigpy_plugin_sanity_check(self, NwkId) + return False - if "Distance" in ClusterType and WidgetType == "Distance": - # value is a str containing all Distance information in cm - nValue = 0 - sValue = value - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=True) + if ( "Health" in self.ListOfDevices[NwkId] and self.ListOfDevices[NwkId]["Health"] == "Disabled" ): + # If the device has been disabled, just drop the message + self.log.logging("Widget", "Debug", "MajDomoDevice - disabled device: %s/%s droping message " % (NwkId, Ep), NwkId) + return False - if "Lux" in ClusterType and WidgetType == "Lux": - nValue = int(value) - sValue = value - UpdateDevice_v2(self, Devices, DeviceUnit, nValue, sValue, BatteryLevel, SignalLevel, ForceUpdate_=False) + if Ep not in self.ListOfDevices[NwkId]["Ep"]: + self.log.logging("Widget", "Error", "MajDomoDevice - %s/%s not known Endpoint" % (NwkId, Ep), NwkId) + return False + + if ( + "Status" in self.ListOfDevices[NwkId] + and self.ListOfDevices[NwkId]["Status"] == "erasePDM" + and "autoRestore" in self.pluginconf.pluginConf + and self.pluginconf.pluginConf["autoRestore"] + ): + # Most likely we have request a coordinator re-initialisation and the latest backup has been put in place + # simply put the device back + self.ListOfDevices[NwkId]["Status"] = "inDB" + + elif "Status" in self.ListOfDevices[NwkId] and self.ListOfDevices[NwkId]["Status"] != "inDB": + self.log.logging( + "Widget", + "Log", + "MajDomoDevice NwkId: %s status: %s not inDB request IEEE for possible reconnection" % (NwkId, self.ListOfDevices[NwkId]["Status"]), + NwkId, + ) + if not zigpy_plugin_sanity_check(self, NwkId): + # Broadcast to 0xfffd: macRxOnWhenIdle = TRUE + zdp_IEEE_address_request(self, 'fffd', NwkId, u8RequestType="00", u8StartIndex="00") + return False - # Check if this Device belongs to a Group. In that case update group - CheckUpdateGroup(self, NWKID, Ep, clusterID) + + if "IEEE" not in self.ListOfDevices[NwkId]: + self.log.logging("Widget", "Error", "MajDomoDevice - no IEEE for %s" % NwkId, NwkId) + return False + + return True + + +def retreive_device_unit( self, Devices, NwkId, Ep, device_id_ieee, ClusterId, WidgetId ): + """ Retreive the Device Unit from the Plugin Database (ClusterType information), then check that unit exists in the Domoticz Devices """ + + device_unit = find_widget_unit_from_WidgetID(self, Devices, WidgetId ) + + if device_unit is None: + self.log.logging( "Widget", "Error", "Device %s not found !!!" % WidgetId, NwkId) + # House keeping, we need to remove this bad clusterType + if remove_bad_cluster_type_entry(self, NwkId, Ep, ClusterId, WidgetId ): + self.log.logging( "Widget", "Log", "WidgetID %s not found, successfully remove the entry from device" % WidgetId, NwkId) + else: + self.log.logging( "Widget", "Error", "WidgetID %s not found, unable to remove the entry from device" % WidgetId, NwkId) + return None + + elif not domo_check_unit(self, Devices, device_id_ieee, device_unit): + # device_id_ieee, device_unit not in Devices !!! + return None + + return device_unit def CheckUpdateGroup(self, NwkId, Ep, ClusterId): @@ -1478,7 +1461,7 @@ def CheckUpdateGroup(self, NwkId, Ep, ClusterId): self.groupmgt.checkAndTriggerIfMajGroupNeeded(NwkId, Ep, ClusterId) -def get_dimmer_level_of_color(self, value): +def getDimmerLevelOfColor(self, value): nValue = 1 analogValue = value if isinstance(value, int) else int(value, 16) @@ -1486,47 +1469,65 @@ def get_dimmer_level_of_color(self, value): sValue = 100 else: sValue = min(round((analogValue / 255) * 100), 100) - sValue = max(sValue, 1) + sValue = max(sValue, 1) if sValue > 0 else 0 return nValue, sValue + def check_erratic_value(self, NwkId, value_type, value, expected_min, expected_max): """ Check if the value is in the range or not. If out of range and disableTrackingValue not set, will check for 5 consecutive errors to log as an error. - Return False if the value is in the range - Return True if the value is out of range + Returns False if the value is in the range, True if the value is out of range. """ + attribute_key = "Erratic_" + value_type + tracking_disable = _get_disable_tracking_eratic_value(self, NwkId) - _attribute = "Erratic_" + value_type - tracking_disable = self.ListOfDevices.get(NwkId, {}).get("Param", {}).get("disableTrackingEraticValue", False) - - valid_value = expected_min < value < expected_max - - if valid_value: - self.ListOfDevices[NwkId].pop(_attribute, None) + if expected_min < value < expected_max: + # Value is in the thresholds, everything is fine + _clear_erratic_attribute(self, NwkId, attribute_key) return False - elif tracking_disable: + if tracking_disable: return True - # We have an erratic value and we have to track. Let's try to handle some erratic values. - if _attribute not in self.ListOfDevices[NwkId]: - self.ListOfDevices[NwkId][_attribute] = {"ConsecutiveErraticValue": 1} - else: - self.ListOfDevices[NwkId][_attribute]["ConsecutiveErraticValue"] += 1 - - consecutive_erratic_value = self.ListOfDevices[NwkId][_attribute]["ConsecutiveErraticValue"] + # We have an erratic value and we have to track, let's try to handle some erratic values + consecutive_erratic_value = _increment_consecutive_erratic_value(self, NwkId, attribute_key) if consecutive_erratic_value > 5: - self.log.logging("Widget", "Error", "Aberrant %s: %s (below %s or above %s) for device: %s" % ( - value_type, value, expected_min, expected_max, NwkId), NwkId) - self.ListOfDevices[NwkId].pop(_attribute, None) + _log_erratic_value_error(self, NwkId, value_type, value, expected_min, expected_max) + _clear_erratic_attribute(self, NwkId, attribute_key) return True - self.log.logging("Widget", "Debug", "Aberrant %s: %s (below %s or above %s) for device: %s [%s]" % ( - value_type, value, expected_min, expected_max, NwkId, consecutive_erratic_value), NwkId) + _log_erratic_value_debug(self, NwkId, value_type, value, expected_min, expected_max, consecutive_erratic_value) return True + +def _get_disable_tracking_eratic_value(self, NwkId): + param_data = self.ListOfDevices.get(NwkId, {}).get("Param", {}) + return param_data.get("disableTrackingEraticValue", False) + + +def _increment_consecutive_erratic_value(self, NwkId, attribute_key): + device_data = self.ListOfDevices.setdefault(NwkId, {}) + erratic_data = device_data.setdefault(attribute_key, {"ConsecutiveErraticValue": 0}) + erratic_data["ConsecutiveErraticValue"] += 1 + return erratic_data["ConsecutiveErraticValue"] + + +def _clear_erratic_attribute(self, NwkId, attribute_key): + device_data = self.ListOfDevices.get(NwkId, {}) + if attribute_key in device_data: + del device_data[attribute_key] + + +def _log_erratic_value_error(self, NwkId, value_type, value, expected_min, expected_max): + self.log.logging("Widget", "Error", f"Aberrant {value_type}: {value} (below {expected_min} or above {expected_max}) for device: {NwkId}", NwkId) + + +def _log_erratic_value_debug(self, NwkId, value_type, value, expected_min, expected_max, consecutive_erratic_value): + self.log.logging("Widget", "Debug", f"Aberrant {value_type}: {value} (below {expected_min} or above {expected_max}) for device: {NwkId} [{consecutive_erratic_value}]", NwkId) + + def check_set_meter_widget( self, Devices, DeviceId, Unit, mode): # Mode = 0 - From device (default) # Mode = 1 - Computed @@ -1534,10 +1535,14 @@ def check_set_meter_widget( self, Devices, DeviceId, Unit, mode): sMode = "%s" %mode Options = {'EnergyMeterMode': '0'} + + _device_options = domo_read_Options( self, Devices, DeviceId, Unit,) + self.log.logging( "Widget", "Debug", "check_set_meter_widget Options: %s" %_device_options) + # Do we have the Energy Mode calculation already set ? - if "EnergyMeterMode" in Devices[Unit].Options: + if "EnergyMeterMode" in _device_options: # Yes, let's retreive it - Options = Devices[Unit].Options + Options = _device_options if Options["EnergyMeterMode"] != sMode: oldnValue, oldsValue = domo_read_nValue_sValue(self, Devices, DeviceId, Unit) @@ -1546,7 +1551,6 @@ def check_set_meter_widget( self, Devices, DeviceId, Unit, mode): domo_update_api(self, Devices, DeviceId, Unit, oldnValue, oldsValue, Options=Options ,) - def retrieve_data_from_current(self, Devices, DeviceID, Unit, _format): """ Retrieve data from current. @@ -1589,7 +1593,7 @@ def retrieve_data_from_current(self, Devices, DeviceID, Unit, _format): return result_list -def normalized_lvl_value( self, Devices, DeviceID, DeviceUnit, value ): +def normalized_lvl_value( switchType, value ): # Normalize sValue vs. analog value coomming from a ReadAttribute analogValue = value if isinstance( value, int) else int(value, 16) @@ -1603,8 +1607,7 @@ def normalized_lvl_value( self, Devices, DeviceID, DeviceUnit, value ): normalized_value = 1 # Looks like in the case of the Profalux shutter, we never get 0 or 100 - _switchtype, _, _ = domo_read_SwitchType_SubType_Type(self, Devices, DeviceID, DeviceUnit) - if _switchtype in (13, 14, 15, 16): + if switchType in (13, 14, 15, 16): if normalized_value == 1 and analogValue == 1: normalized_value = 0 if normalized_value == 99 and analogValue == 254: @@ -1613,29 +1616,6 @@ def normalized_lvl_value( self, Devices, DeviceID, DeviceUnit, value ): return normalized_value -def getDimmerLevelOfColor(self, value): - nValue = 1 - analogValue = value if isinstance(value, int) else int(value, 16) - - if analogValue >= 255: - sValue = 100 - else: - sValue = min(round((analogValue / 255) * 100), 100) - sValue = max(sValue, 1) if sValue > 0 else 0 - - return nValue, sValue - -def check_and_update_db_status( self, NWKID): - if ( - "Status" in self.ListOfDevices[NWKID] - and self.ListOfDevices[NWKID]["Status"] == "erasePDM" - and "autoRestore" in self.pluginconf.pluginConf - and self.pluginconf.pluginConf["autoRestore"] - ): - # Most likely we have request a coordinator re-initialisation and the latest backup has been put in place - # simply put the device back - self.ListOfDevices[NWKID]["Status"] = "inDB" - def is_PowerNegative_widget( ClusterTypeList): return any( _widget_type == "ProdMeter" for _, _, _widget_type in ClusterTypeList ) @@ -1647,6 +1627,7 @@ def calculate_humidity_status(humidity_value): return 1 else: return 3 + def calculate_baro_forecast(baroValue): @@ -1661,4 +1642,23 @@ def calculate_baro_forecast(baroValue): def str_round(value, n): - return "{:.{n}f}".format(value, n=int(n)) \ No newline at end of file + return "{:.{n}f}".format(value, n=int(n)) + + +def baro_adjustement_value(self, Devices, NwkId, DeviceId, Device_Unit): + if self.domoticzdb_DeviceStatus: + try: + return round(self.domoticzdb_DeviceStatus.retreiveAddjValue_baro(domo_read_Device_Idx(self, Devices, DeviceId, Device_Unit,)), 1) + except Exception as e: + self.log.logging("Widget", "Error", "Error while trying to get Adjusted Value for Baro %s %s" % ( + NwkId, e), NwkId) + return 0 + +def temp_adjustement_value(self, Devices, NwkId, DeviceId, Device_Unit): + if self.domoticzdb_DeviceStatus: + try: + return round(self.domoticzdb_DeviceStatus.retreiveAddjValue_temp(domo_read_Device_Idx(self, Devices, DeviceId, Device_Unit,)), 1) + except Exception as e: + self.log.logging("Widget", "Error", "Error while trying to get Adjusted Value for Temp %s %s" % ( + NwkId, e), NwkId) + return 0 \ No newline at end of file diff --git a/Modules/domoticzAbstractLayer.py b/Modules/domoticzAbstractLayer.py index deb2703e8..dfd82060e 100644 --- a/Modules/domoticzAbstractLayer.py +++ b/Modules/domoticzAbstractLayer.py @@ -16,6 +16,7 @@ DELAY_BETWEEN_TOUCH = 30 + def load_list_of_domoticz_widget(self, Devices): """Use at plugin start to creat an index of Domoticz Widget. It is also called after a Widget removal and when a new device has been paired. @@ -326,6 +327,12 @@ def domo_read_nValue_sValue(self, Devices, DeviceID, Unit): def domo_read_TimedOut( self, Devices, DeviceId_, Unit_, ): return ( Devices[DeviceId_].Units[Unit_].TimedOut if DOMOTICZ_EXTENDED_API else Devices[Unit_].TimedOut ) +def domo_read_Options( self, Devices, DeviceId_, Unit_,): + return ( Devices[DeviceId_].Units[Unit_].Options if DOMOTICZ_EXTENDED_API else Devices[Unit_].Options ) + +def domo_read_Device_Idx(self, Devices, DeviceId_, Unit_,): + return ( Devices[DeviceId_].Units[Unit_].ID if DOMOTICZ_EXTENDED_API else Devices[Unit_].ID ) + def domo_check_unit(self, Devices, DeviceId_, Unit_): if DOMOTICZ_EXTENDED_API: return Unit_ in Devices[DeviceId_].Units @@ -419,4 +426,47 @@ def timeout_widget_api(self, Devices, DeviceId_, Unit_, timeout_value): def domoticz_log_api( message): - Domoticz.Log( message ) \ No newline at end of file + Domoticz.Log( message ) + +def is_dimmable_switch(self, Devices, DeviceId, Unit): + _switchType, _subType, _type = domo_read_SwitchType_SubType_Type(self, Devices, DeviceId, Unit) + if check_widget(_switchType, _subType, _type) == "Dimmable_Switch": + return find_partially_opened_nValue(_switchType, _subType, _type) + return None + + +def is_dimmable_light(self, Devices, DeviceId, Unit): + _switchType, _subType, _type = domo_read_SwitchType_SubType_Type(self, Devices, DeviceId, Unit) + if check_widget(_switchType, _subType, _type) == "Dimmable_Light": + return find_partially_opened_nValue(_switchType, _subType, _type) + return None + + +def is_dimmable_blind(self, Devices, DeviceId, Unit): + _switchType, _subType, _type = domo_read_SwitchType_SubType_Type(self, Devices, DeviceId, Unit) + if check_widget(_switchType, _subType, _type) == "Blind": + return find_partially_opened_nValue(_switchType, _subType, _type) + return None + + +DIMMABLE_WIDGETS = { + (7, 1, 241): { "Widget": "Dimmable_Light", "Name": "RGBW", "partially_opened_nValue": 15}, + (7, 2, 241): { "Widget": "Dimmable_Light", "Name": "RGB", "partially_opened_nValue": 15}, + (7, 4, 241): { "Widget": "Dimmable_Light", "Name": "RGBWW", "partially_opened_nValue": 15}, + (7, 7, 241): { "Widget": "Dimmable_Light", "Name": "RGBWWZ", "partially_opened_nValue": 15}, + (7, 8, 241): { "Widget": "Dimmable_Light", "Name": "WW Switch", "partially_opened_nValue": 15}, + (7, 73, 244): { "Widget": "Dimmable_Switch", "Name": "Dimmer", "partially_opened_nValue": 2}, + (14, 73, 244): { "Widget": "Blind", "Name": "Venetian Blinds US", "partially_opened_nValue": 17}, + (13, 73, 244): { "Widget": "Blind", "Name": "Blind Percentage", "partially_opened_nValue": 2}, + (15, 73, 244): { "Widget": "Blind", "Name": "Venetian Blinds EU", "partially_opened_nValue": 17}, + (21, 73, 244): { "Widget": "Blind", "Name": "Blinds + Stop", "partially_opened_nValue": 2}, +} + +def find_partially_opened_nValue(switch_type, sub_type, widget_type): + key = (switch_type, sub_type, widget_type) + return DIMMABLE_WIDGETS.get(key).get("partially_opened_nValue") + + +def check_widget(switch_type, sub_type, widget_type): + key = (switch_type, sub_type, widget_type) + return DIMMABLE_WIDGETS.get(key).get("Widget")