Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tuya TS0004 Smart Switch relay 4CH #1207

Merged
merged 3 commits into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 13 additions & 56 deletions Conf/Certified/Tuya/TS0004-_TZ3000_excgg5kb.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,70 +37,27 @@
"0006": "",
"e001": "",
"Type": "Switch"
},
"f2": {
"0021": "",
"Type": ""
}
},
"Type": "",
"ClusterToBind": [
"0006"
],
"ConfigureReporting": {
"0006": {
"Attributes": {
"0000": {
"DataType": "10",
"MinInterval": "0001",
"MaxInterval": "012C",
"TimeOut": "0258",
"Change": "01"
}
}
}
},
"ReadAttributes": {
"0000": [
"0004",
"0000",
"0001",
"0005",
"0007",
"fffe",
"0002",
"0003",
"0004",
"0006"
],
"0006": [
"0000",
"4001",
"4002",
"5000",
"8000",
"8001",
"8002"
],
"e000": [
"d001",
"d002",
"d003"
],
"e001": [
"d010",
"d030"
],
"0019": [
"0001",
"0002",
"0003",
"0004",
"0005",
"0006",
"0007",
"0008",
"0009"
]
"0000": [ "0004", "0000", "0001", "0005", "0007", "fffe", "0002", "0003", "0004", "0006" ],
"0006": [ "0000", "4001", "4002", "5000", "8000", "8001", "8002" ],
"e000": [ "d001", "d002", "d003" ],
"e001": [ "d010" ],
"0019": [ "0001", "0002", "0003", "0004", "0005", "0006", "0007", "0008", "0009" ]
},
"Param": {
"TuyaSwitchMode": "Toggle",
"PowerOnAfterOffOn": "2"
"SmartSwitchBackLight": 1,
"SmartSwitchIndicateLight": 1,
"PowerOnAfterOffOn": "0"
}
}
}
32 changes: 12 additions & 20 deletions Modules/basicOutputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,43 +649,35 @@ def set_poweron_afteroffon(self, key, OnOffMode=0xFF):
if key not in self.ListOfDevices:
self.log.logging("BasicOutput", "Error", "set_PowerOn_OnOff for %s not found" % (key), key)
return

model_name = ""
if "Model" in self.ListOfDevices[key]:
model_name = self.ListOfDevices[key]["Model"]

manuf_spec = "00"
manuf_id = "0000"

ListOfEp = getListOfEpForCluster(self, key, "0006")
cluster_id = "0006"
attribute = "4003"
data_type = "30" #

if model_name in ( "TS0121", "TS0115", "TS011F-multiprise", "TS011F-2Gang-switches", "TS011F-plug" ):
if model_name in ( "TS0121", "TS0115", "TS011F-multiprise", "TS011F-2Gang-switches", "TS011F-plug" , "TS0004-_TZ3000_excgg5kb", ):
attribute = "8002"
if OnOffMode == 0xFF:
OnOffMode = 0x02

data_type = "30" #
ListOfEp = getListOfEpForCluster(self, key, "0006")
if model_name in ( "TS0004-_TZ3000_excgg5kb",):
ListOfEp = ( "01", )

self.log.logging( "BasicOutput", "Debug", "set_PowerOn_OnOff for %s - OnOff: %s %s %s" % (key, OnOffMode, attribute, ListOfEp), key )

for EPout in ListOfEp:
data = "%02x" % OnOffMode
self.log.logging(
"BasicOutput", "Debug", "set_PowerOn_OnOff for %s/%s - OnOff: %s" % (key, EPout, OnOffMode), key
)
data = "%02x" % int(OnOffMode)
self.log.logging( "BasicOutput", "Debug", "set_PowerOn_OnOff for %s/%s - OnOff: %s" % (key, EPout, OnOffMode), key )
if attribute in self.ListOfDevices[key]["Ep"][EPout]["0006"]:
del self.ListOfDevices[key]["Ep"][EPout]["0006"][attribute]
return write_attribute(
self,
key,
ZIGATE_EP,
EPout,
cluster_id,
manuf_id,
manuf_spec,
attribute,
data_type,
data,
ackIsDisabled=True,
)
return write_attribute( self, key, ZIGATE_EP, EPout, cluster_id, manuf_id, manuf_spec, attribute, data_type, data, ackIsDisabled=True, )


def unknown_device_nwkid(self, nwkid):
Expand Down
75 changes: 48 additions & 27 deletions Modules/paramDevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@
from Modules.schneider_wiser import (iTRV_open_window_detection,
wiser_home_lockout_thermostat)
from Modules.tools import getEpForCluster
from Modules.tuya import (get_tuya_attribute, tuya_backlight_command,
from Modules.tuya import (SmartRelayStatus01, SmartRelayStatus02,
SmartRelayStatus03, SmartRelayStatus04,
get_tuya_attribute, tuya_backlight_command,
tuya_cmd_ts004F, tuya_energy_childLock,
tuya_external_switch_mode, tuya_garage_run_time,
tuya_switch_indicate_light, tuya_switch_relay_status,
tuya_TS0004_back_light, tuya_TS0004_indicate_light,
tuya_window_cover_calibration,
tuya_window_cover_motor_reversal)
from Modules.tuyaSiren import (tuya_siren2_alarm_duration,
Expand Down Expand Up @@ -103,62 +106,58 @@ def param_PowerOnAfterOffOn(self, nwkid, mode):
# 1 - stay On after a Off/On
# 255 - stay to previous state after a Off/On ( or 2 for BlitzWolf)

self.log.logging("Heartbeat", "Debug", "param_PowerOnAfterOffOn for %s mode: %s" % (nwkid, mode), nwkid)
if mode not in (0, 1, 2, 255):
model = ""
if "Model" in self.ListOfDevices[nwkid] and self.ListOfDevices[nwkid]["Model"]:
model = self.ListOfDevices[nwkid] and self.ListOfDevices[nwkid]["Model"]

self.log.logging("Heartbeat", "Debug", "param_PowerOnAfterOffOn for %s mode: %s for model: %s " % (nwkid, mode, model), nwkid)
if int(mode) not in (0, 1, 2, 255):
return

if "Manufacturer" not in self.ListOfDevices[nwkid]:
return

if self.ListOfDevices[nwkid]["Manufacturer"] == "100b": # Philips
if "0b" not in self.ListOfDevices[nwkid]["Ep"]:
return
if "0006" not in self.ListOfDevices[nwkid]["Ep"]["0b"]:
return
if "4003" not in self.ListOfDevices[nwkid]["Ep"]["0b"]["0006"]:
if not _check_attribute_exist( self, nwkid, "0b", "0006", "4003"):
return

if self.ListOfDevices[nwkid]["Ep"]["0b"]["0006"]["4003"] != str(mode):
self.log.logging("Heartbeat", "Debug", "param_PowerOnAfterOffOn for Philips for %s mode: %s" % (nwkid, mode), nwkid)
philips_set_poweron_after_offon_device(self, mode, nwkid)
ReadAttributeRequest_0006_400x(self, nwkid)

elif "Model" in self.ListOfDevices[nwkid] and self.ListOfDevices[nwkid]["Model"] in (
elif model in (
"TS0121",
"TS0115",
"TS011F-multiprise",
"TS011F-2Gang-switches",
"TS011F-plug",
"TS0004"
"TS0004",
"TS0004-_TZ3000_excgg5kb",
):
self.log.logging("Heartbeat", "Debug", "param_PowerOnAfterOffOn for %s mode: %s TUYA Manufacturer" % (nwkid, mode), nwkid)
# Tuya ( 'TS0121' BlitzWolf )
if "01" not in self.ListOfDevices[nwkid]["Ep"]:
return
if "0006" not in self.ListOfDevices[nwkid]["Ep"]["01"]:
return
if "8002" not in self.ListOfDevices[nwkid]["Ep"]["01"]["0006"]:

if not _check_attribute_exist( self, nwkid, "01", "0006", "8002"):
return

if self.ListOfDevices[nwkid]["Ep"]["01"]["0006"]["8002"] == "2" and str(mode) == "255":
return

if self.ListOfDevices[nwkid]["Ep"]["01"]["0006"]["8002"] != str(mode):
self.log.logging("Heartbeat", "Debug", "param_PowerOnAfterOffOn for Tuya for %s mode: %s" % (nwkid, mode), nwkid)
set_poweron_afteroffon(self, nwkid, mode)
ReadAttributeRequest_0006_400x(self, nwkid)

elif self.ListOfDevices[nwkid]["Manufacturer"] == "1277": # Enki Leroy Merlin
if "01" not in self.ListOfDevices[nwkid]["Ep"]:
return
if "0006" not in self.ListOfDevices[nwkid]["Ep"]["01"]:
return
if "4003" not in self.ListOfDevices[nwkid]["Ep"]["01"]["0006"]:
if not _check_attribute_exist( self, nwkid, "01", "0006", "4003"):
return

if self.ListOfDevices[nwkid]["Ep"]["01"]["0006"]["4003"] != str(mode):
self.log.logging("Heartbeat", "Debug", "param_PowerOnAfterOffOn for Enki for %s mode: %s" % (nwkid, mode), nwkid)
enki_set_poweron_after_offon_device(self, mode, nwkid)
ReadAttributeRequest_0006_400x(self, nwkid)

elif "Model" in self.ListOfDevices[nwkid] and self.ListOfDevices[nwkid]["Model"] in (
elif model in (
"TS0601-switch",
"TS0601-2Gangs-switch",
"TS0601-Energy",
Expand All @@ -169,16 +168,32 @@ def param_PowerOnAfterOffOn(self, nwkid, mode):
else:
# Ikea, Legrand,
for ep in self.ListOfDevices[nwkid]["Ep"]:
if "0006" not in self.ListOfDevices[nwkid]["Ep"][ep]:
if not _check_attribute_exist( self, nwkid, ep, "0006", "4003"):
continue
if "4003" in self.ListOfDevices[nwkid]["Ep"][ep]["0006"] and self.ListOfDevices[nwkid]["Ep"][ep]["0006"]["4003"] == str(mode):

if self.ListOfDevices[nwkid]["Ep"][ep]["0006"]["4003"] == str(mode):
continue
elif "8002" in self.ListOfDevices[nwkid]["Ep"][ep]["0006"] and self.ListOfDevices[nwkid]["Ep"][ep]["0006"]["8002"] == str(mode):
elif not _check_attribute_exist( self, nwkid, ep, "0006", "8002") and self.ListOfDevices[nwkid]["Ep"][ep]["0006"]["8002"] == str(mode):
continue

self.log.logging("Heartbeat", "Debug", "param_PowerOnAfterOffOn for %s mode: %s" % (nwkid, mode), nwkid)
set_poweron_afteroffon(self, nwkid, mode)
ReadAttributeRequest_0006_400x(self, nwkid)

def _check_attribute_exist( self, nwkid, ep, cluster, attribute):
if ep not in self.ListOfDevices[nwkid]["Ep"]:
self.log.logging("Heartbeat", "Log", "No ep: %s" %ep, nwkid)
return False
if cluster not in self.ListOfDevices[nwkid]["Ep"][ ep ]:
self.log.logging("Heartbeat", "Log", "No Cluster: %s" %cluster, nwkid)
return False
if attribute not in self.ListOfDevices[nwkid]["Ep"][ ep ][ cluster ]:
self.log.logging("Heartbeat", "Log", "No Attribute: %s" %attribute, nwkid)
return False
return True



def ias_wd_sirene_max_alarm_dureation( self, nwkid, duration):
if self.iaszonemgt:
Epout = getEpForCluster(self, nwkid, "0502", strict=True)
Expand Down Expand Up @@ -223,7 +238,13 @@ def ias_wd_sirene_max_alarm_dureation( self, nwkid, duration):
"TuyaAlarmMelody": tuya_siren2_alarm_melody,
"SireneMaxAlarmDuration": ias_wd_sirene_max_alarm_dureation,
"TuyaGarageOpenerRunTime": tuya_garage_run_time,
"TuyaSwitchMode": tuya_external_switch_mode
"TuyaSwitchMode": tuya_external_switch_mode,
"SmartSwitchBackLight": tuya_TS0004_back_light,
"SmartSwitchIndicateLight": tuya_TS0004_indicate_light,
"SmartRelayStatus01": SmartRelayStatus01,
"SmartRelayStatus02": SmartRelayStatus02,
"SmartRelayStatus03": SmartRelayStatus03,
"SmartRelayStatus04": SmartRelayStatus04,
}

def sanity_check_of_param(self, NwkId):
Expand Down
42 changes: 26 additions & 16 deletions Modules/readClusters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,33 +1283,43 @@ def Cluster0006(self, Devices, MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAt
)
checkAndStoreAttributeValue(self, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, str(decodeAttribute(self, MsgAttType, MsgClusterData)))

elif MsgAttrID == "8000" and "Model" in self.ListOfDevices[MsgSrcAddr] and self.ListOfDevices[MsgSrcAddr]["Model"] in ("lumi.sensor_switch", "lumi.sensor_switch.aq2", ):
elif MsgAttrID == "5000":
# Back light for Tuya Smart Relay CH4
self.log.logging(
"Cluster",
"Debug",
"readCluster - %s - %s/%s Back Light: %s %s %s %s " % (MsgClusterId, MsgSrcAddr, MsgSrcEp, MsgAttrID, MsgAttType, MsgAttSize, MsgClusterData),
MsgSrcAddr,
)
checkAndStoreAttributeValue(self, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, str(decodeAttribute(self, MsgAttType, MsgClusterData)))

elif MsgAttrID == "8000" and "Model" in self.ListOfDevices[MsgSrcAddr] and self.ListOfDevices[MsgSrcAddr]["Model"] in ("lumi.sensor_switch", "lumi.sensor_switch.aq2", ):
MajDomoDevice(self, Devices, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgClusterData)
checkAndStoreAttributeValue(self, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, MsgClusterData)

self.log.logging(
"Cluster",
"Debug",
"ReadCluster - ClusterId=0006 - reception General: On/Off: %s for Mija Button" % str(MsgClusterData),
MsgSrcAddr,
)

elif MsgAttrID == "8000":
# On/Off for particular devices
self.log.logging(
"Cluster",
"Log",
"ReadCluster - ClusterId=0006 - NwkId: %s Ep: %s Attr: %s Value: %s (if something doesn't work anymore, please contact @pipiche" % (
MsgSrcAddr, MsgSrcEp, MsgAttrID, MsgClusterData),
MsgSrcAddr,
)
if "Model" in self.ListOfDevices[MsgSrcAddr] and self.ListOfDevices[MsgSrcAddr]["Model"] not in ( "TS0004-_TZ3000_excgg5kb", ):
self.log.logging(
"Cluster",
"Log",
"ReadCluster - ClusterId=0006 - NwkId: %s Ep: %s Attr: %s Value: %s (if something doesn't work anymore, please contact @pipiche" % (
MsgSrcAddr, MsgSrcEp, MsgAttrID, MsgClusterData),
MsgSrcAddr,
)
checkAndStoreAttributeValue(self, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, str(decodeAttribute(self, MsgAttType, MsgClusterData)))

elif MsgAttrID == "8001":
# Tuya SMart Relay CH4 Indicate Light
self.log.logging(
"Cluster",
"Log",
"readCluster - %s - %s/%s unknown attribute: %s %s %s %s " % (MsgClusterId, MsgSrcAddr, MsgSrcEp, MsgAttrID, MsgAttType, MsgAttSize, MsgClusterData),
"Debug",
"readCluster - %s - %s/%s Indicate Light: %s %s %s %s " % (MsgClusterId, MsgSrcAddr, MsgSrcEp, MsgAttrID, MsgAttType, MsgAttSize, MsgClusterData),
MsgSrcAddr,
)
checkAndStoreAttributeValue(self, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, str(decodeAttribute(self, MsgAttType, MsgClusterData)))
Expand Down Expand Up @@ -1941,7 +1951,7 @@ def Cluster0019(self, Devices, MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAt

self.log.logging(
"Cluster",
"Log",
"Debug",
"ReadCluster %s - %s/%s Attribute: %s Type: %s Size: %s Data: %s" % (MsgClusterId, MsgSrcAddr, MsgSrcEp, MsgAttrID, MsgAttType, MsgAttSize, MsgClusterData),
MsgSrcAddr,
)
Expand Down Expand Up @@ -4516,7 +4526,7 @@ def Cluster0b05(self, Devices, MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAt
def Clustere000(self, Devices, MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, MsgAttType, MsgAttSize, MsgClusterData, Source):
self.log.logging(
"Cluster",
"Log",
"Debug",
"ReadCluster - %s - %s/%s MsgAttrID: %s, MsgAttType: %s, MsgAttSize: %s, : %s" % (MsgClusterId, MsgSrcAddr, MsgSrcEp, MsgAttrID, MsgAttType, MsgAttSize, MsgClusterData),
MsgSrcAddr,
)
Expand All @@ -4537,7 +4547,7 @@ def Clustere000(self, Devices, MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAt
def Clustere001(self, Devices, MsgSQN, MsgSrcAddr, MsgSrcEp, MsgClusterId, MsgAttrID, MsgAttType, MsgAttSize, MsgClusterData, Source):
self.log.logging(
"Cluster",
"Log",
"Debug",
"ReadCluster - %s - %s/%s MsgAttrID: %s, MsgAttType: %s, MsgAttSize: %s, : %s" % (MsgClusterId, MsgSrcAddr, MsgSrcEp, MsgAttrID, MsgAttType, MsgAttSize, MsgClusterData),
MsgSrcAddr,
)
Expand Down
Loading