Skip to content

Commit

Permalink
Lighting color control / Fixing Lidl TS0505A behaviour (#1657)
Browse files Browse the repository at this point in the history
* TS0505A exist with different Manufacturer Name and it seems that they are not controlled on the same way.
  • Loading branch information
pipiche38 authored Oct 29, 2023
1 parent 2365062 commit ba1b776
Show file tree
Hide file tree
Showing 11 changed files with 357 additions and 48 deletions.
55 changes: 55 additions & 0 deletions Conf/Local-Devices/TS0505A-HueSaturation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"_comment": "Tuya RR400ZB require Tuya HueandSaturation",
"_blakadder": "https://zigbee.blakadder.com/Lidl_HG06104A.html",
"_version": "1.0",
"Identifier" : [
["TS0505A", "_TZ3000_dbou1ap4"]
],
"Ep": {
"01": {
"0000": "",
"0003": "",
"0004": "",
"0005": "",
"0006": "",
"0008": "",
"0300": {
"Attributes": {
"f000": {"Enabled": true, "Name": "ColorMode", "DataType": "20", "ActionList": [ "check_store_value"] },
"f001": {"Enabled": true, "Name": "Brightness ", "DataType": "20", "ActionList": [ "check_store_value"] },
"f003": {"Enabled": true, "Name": "SceneData", "DataType": "48", "ActionList": [ "check_store_value"] }
}
},
"000a": "",
"0019": "",
"1000": "",
"ef00": "",
"Type": "ColorControlRGBWW"
},
"f2": {
"0021": "",
"Type": ""
}
},
"Type": "",
"bindEp": "01",
"ClusterToBind": [ ],
"ConfigureReporting": {
},
"ReadAttributes": {
"0000": [ "0000", "0001", "0002", "0003", "0004", "0005", "0006", "0007" ],
"0006": [ "0000", "4001", "4002" ],
"0008": [ "0000" ],
"0019": [],
"0300": [ "f002", "f00d", "0000", "0001", "0003", "0004", "0007", "0008", "000f" ]
},
"TUYA_REGISTRATION": 13,
"TuyaCommandF0": true,
"FORCE_COLOR_COMMAND": "TuyaMovetoHueandSaturation",
"TUYAColorControlRgbMode": true,
"Param": {
"moveToColourTemp": "0010",
"moveToColourRGB": "0010",
"moveToHueSatu": "0000"
}
}
50 changes: 50 additions & 0 deletions Conf/Local-Devices/TS0505A.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"_comment": "Tuya RR400ZB able to manage color via MoveToColour",
"_blakadder": "https://zigbee.blakadder.com/Lidl_HG06104A.html",
"_version": "1.0",
"Ep": {
"01": {
"0000": "",
"0003": "",
"0004": "",
"0005": "",
"0006": "",
"0008": "",
"0300": {
"Attributes": {
"f000": {"Enabled": true, "Name": "Tuya0300_f000", "DataType": "20", "ActionList": [ "check_store_value"] },
"f003": {"Enabled": true, "Name": "Tuya0300_f003", "DataType": "48", "ActionList": [ "check_store_value"] }
}
},
"000a": "",
"0019": "",
"1000": "",
"ef00": "",
"Type": "ColorControlRGBWW"
},
"f2": {
"0021": "",
"Type": ""
}
},
"Type": "",
"bindEp": "01",
"ClusterToBind": [ ],
"ConfigureReporting": {
},
"ReadAttributes": {
"0000": [ "0000", "0001", "0002", "0003", "0004", "0005", "0006", "0007" ],
"0006": [ "0000", "4001", "4002" ],
"0008": [ "0000" ],
"0019": [],
"0300": [ "f002", "f00d", "0000", "0001", "0003", "0004", "0007", "0008", "000f" ]
},
"TUYA_REGISTRATION": 13,
"TuyaCommandF0": true,
"TUYAColorControlRgbMode": true,
"Param": {
"moveToColourTemp": "0010",
"moveToColourRGB": "0010",
"moveToHueSatu": "0000"
}
}
43 changes: 43 additions & 0 deletions Conf/Local-Devices/TS0601-Human-Presence.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"_source": "https://github.com/zigbeefordomoticz/z4d-certified-devices/issues/11",
"_blakadder": "https://zigbee.blakadder.com/Tuya_ZY-M100-24G.html",
"_description": "uya Human Presence Detector 5.8GHz Ceiling Mount ZY-M100-2",
"Ep": {
"01": {
"0000": "",
"0004": "",
"0005": "",
"0500": "",
"000a": "",
"0019": "",
"Type": "Motion/Lux"
}
},
"Identifier": [
[ "TS0601", "_TZE200_bh3n6gk8" ],
[ "TS0601", "_TZE200_3towulqd" ],
[ "TS0601", "_TZE200_1ibpyhdc" ]
],
"Type": "",
"ClusterToBind": [ ],
"ConfigureReporting": {},
"ReadAttributes": {
"0000": [ "0004", "0000", "0001", "0005", "0007", "fffe" ],
"0001": [],
"0019": [],
"0500": [ "0000", "0001", "0002", "0010", "0011"],
"ef00": []
},
"TS0601_DP": {
"68": { "sensor_type": "illuminance"},
"69": { "sensor_type": "motion", "EvalExp": "int(value == 0)", "DomoDeviceFormat": "str"},
"6a": { "store_tuya_attribute": "Sensitivity"},
"6b": { "store_tuya_attribute": "max_range"},
"6c": { "store_tuya_attribute": "min_range"},
"6d": { "store_tuya_attribute": "target_distace"},
"6e": { "store_tuya_attribute": "fading_time"},
"6f": { "store_tuya_attribute": "detection_delay"}
},
"Param": {
}
}
128 changes: 99 additions & 29 deletions Modules/actuators.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,16 @@
import json

from Modules.basicOutputs import set_poweron_afteroffon
from Modules.readAttributes import ReadAttributeRequest_0006_400x
from Modules.paramDevice import get_device_config_param
from Modules.readAttributes import (
ReadAttributeRequest_0006_400x,
ReadAttributeRequest_0300_Color_Capabilities)
from Modules.thermostats import thermostat_Setpoint
from Modules.tools import Hex_Format, rgb_to_hsl, rgb_to_xy
from Modules.tools import (Hex_Format, get_deviceconf_parameter_value,
getAttributeValue, rgb_to_hsl, rgb_to_xy)
from Modules.tuya import (tuya_color_control_rgbMode,
tuya_Move_To_Hue_Saturation,
tuya_Move_To_Hue_Saturation_Brightness)
from Modules.zigateConsts import ZIGATE_EP
from Zigbee.zclCommands import (zcl_identify_send, zcl_identify_trigger_effect,
zcl_level_move_to_level,
Expand Down Expand Up @@ -238,34 +245,34 @@ def actuator_setcolor(self, nwkid, EPout, value, Color):
# First manage level
# if Hue_List['m'] or Hue_List['m'] != 9998 or manage_level:
transitionMoveLevel = "0000"
if (
"Param" in self.ListOfDevices[nwkid]
and "moveToLevel" in self.ListOfDevices[nwkid]["Param"]
):
if ( "Param" in self.ListOfDevices[nwkid] and "moveToLevel" in self.ListOfDevices[nwkid]["Param"] ):
transitionMoveLevel = "%04x" % int(self.ListOfDevices[nwkid]["Param"]["moveToLevel"])

if Hue_List["m"] or Hue_List["m"] != 9998:
value = lightning_percentage_to_analog( value )
self.log.logging("Command", "Debug", "---------- Set Level: %s" % (value), nwkid)
actuator_setlevel(self, nwkid, EPout, value, "Light", transitionMoveLevel)

# ColorModeTemp = 2 // White with color temperature. Valid fields: t
force_color_command = get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "FORCE_COLOR_COMMAND", return_default=None)
ColorCapabilitiesList = device_color_capabilities( self, nwkid, EPout)
self.log.logging("Command", "Debug", "actuator_setcolor force_color_command %s" % force_color_command, nwkid)

if Hue_List["m"] == 2:
# ColorModeTemp = 2 // White with color temperature. Valid fields: t
handle_color_mode_2(self, nwkid, EPout, Hue_List)

# ColorModeRGB = 3 // Color. Valid fields: r, g, b.
elif Hue_List["m"] == 3 and force_color_command == "TuyaMovetoHueandSaturation":
handle_color_mode_tuya( self, nwkid, EPout, Hue_List, value)

elif Hue_List["m"] == 3:
# ColorModeRGB = 3 // Color. Valid fields: r, g, b.
handle_color_mode_3(self, nwkid, EPout, Hue_List)

# ColorModeCustom = 4, // Custom (color + white). Valid fields: r, g, b, cw, ww, depending on device capabilities
elif Hue_List["m"] == 4:
# ColorModeCustom = 4, // Custom (color + white). Valid fields: r, g, b, cw, ww, depending on device capabilities
handle_color_mode_4(self, nwkid, EPout, Hue_List )

# With saturation and hue, not seen in domoticz but present on zigate, and some device need it

elif Hue_List["m"] == 9998:
handle_color_mode_9998( self, nwkid, EPout, Hue_List)
# With saturation and hue, not seen in domoticz but present on zigate, and some device need it
handle_color_mode_9998( self, nwkid, EPout, Hue_List, value)

def handle_color_mode_2(self, nwkid, EPout, Hue_List):
# White with color temperature. Valid fields: t
# Value is in mireds (not kelvin)
# Correct values are from 153 (6500K) up to 588 (1700K)
# t is 0 > 255
Expand All @@ -274,15 +281,19 @@ def handle_color_mode_2(self, nwkid, EPout, Hue_List):
self.log.logging( "Command", "Debug", "handle_color_mode_2 Set Temp Kelvin: %s-%s" % (TempMired, Hex_Format(4, TempMired)), nwkid )
transitionMoveLevel , transitionRGB , transitionMoveLevel , transitionHue , transitionTemp = get_all_transition_mode( self, nwkid)
zcl_move_to_colour_temperature( self, nwkid, EPout, Hex_Format(4, TempMired), transitionTemp)


def handle_color_mode_3(self, nwkid, EPout, Hue_List):
# Color. Valid fields: r, g, b.
x, y = rgb_to_xy((int(Hue_List["r"]), int(Hue_List["g"]), int(Hue_List["b"])))
# Convert 0>1 to 0>FFFF
x = int(x * 65536)
y = int(y * 65536)
#strxy = Hex_Format(4, x) + Hex_Format(4, y)
self.log.logging("Command", "Debug", "handle_color_mode_3 Set Temp X: %s Y: %s" % (x, y), nwkid)
transitionMoveLevel , transitionRGB , transitionMoveLevel , transitionHue , transitionTemp = get_all_transition_mode( self, nwkid)
if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None):
tuya_color_control_rgbMode( self, nwkid, "01")
zcl_move_to_colour(self, nwkid, EPout, Hex_Format(4, x), Hex_Format(4, y), transitionRGB)

def handle_color_mode_4(self, nwkid, EPout, Hue_List ):
Expand All @@ -296,9 +307,10 @@ def handle_color_mode_4(self, nwkid, EPout, Hue_List ):
if cw != 0 and ww != 0:
TempKelvin = int((255 - ww) * (6500 - 1700) / 255 + 1700)
TempMired = 1000000 // TempKelvin
self.log.logging(
"Command", "Log", "handle_color_mode_4 Set Temp Kelvin: %s-%s" % (TempMired, Hex_Format(4, TempMired)), nwkid
)
self.log.logging( "Command", "Log", "handle_color_mode_4 Set Temp Kelvin: %s-%s" % (
TempMired, Hex_Format(4, TempMired)), nwkid )
if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None):
tuya_color_control_rgbMode( self, nwkid, "01")
zcl_move_to_colour_temperature( self, nwkid, EPout, Hex_Format(4, TempMired), transitionTemp)

# Process Colour
Expand All @@ -308,10 +320,13 @@ def handle_color_mode_4(self, nwkid, EPout, Hue_List ):
hue = _h * 360 # 0 > 360
hue = int(hue * 254 // 360)

self.log.logging("Command", "Log", "handle_color_mode_4 Set Hue X: %s Saturation: %s" % (hue, saturation), nwkid)
self.log.logging("Command", "Log", "handle_color_mode_4 Set Hue X: %s Saturation: %s" % (
hue, saturation), nwkid)
if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None):
tuya_color_control_rgbMode( self, nwkid, "01")
zcl_move_hue_and_saturation(self, nwkid, EPout, Hex_Format(2, hue), Hex_Format(2, saturation), transitionRGB)
def handle_color_mode_9998( self, nwkid, EPout, Hue_List):

def handle_color_mode_9998( self, nwkid, EPout, Hue_List, value):
transitionMoveLevel , transitionRGB , transitionMoveLevel , transitionHue , transitionTemp = get_all_transition_mode( self, nwkid)
_h, _s, _l = rgb_to_hsl((int(Hue_List["r"]), int(Hue_List["g"]), int(Hue_List["b"])))
saturation = _s * 100 # 0 > 100
Expand All @@ -320,12 +335,35 @@ def handle_color_mode_9998( self, nwkid, EPout, Hue_List):
hue = int(hue * 254 // 360)

self.log.logging("Command", "Debug", "handle_color_mode_9998 Set Hue X: %s Saturation: %s" % (hue, saturation), nwkid)
zcl_move_hue_and_saturation(self, nwkid, EPout, Hex_Format(2, hue), Hex_Format(2, saturation), transitionRGB)
if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None):
tuya_color_control_rgbMode( self, nwkid, "01")

if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "FORCE_COLOR_COMMAND", return_default=None) == "TuyaMovetoHueandSaturation":
tuya_Move_To_Hue_Saturation( self, nwkid, hue, saturation, value)
else:
zcl_move_hue_and_saturation(self, nwkid, EPout, Hex_Format(2, hue), Hex_Format(2, saturation), transitionRGB)
value = lightning_percentage_to_analog( value )
self.log.logging( "Command", "Debug", "handle_color_mode_9998 Set Level: %s instead of Level: %s" % (value, value), nwkid)
actuator_setlevel(self, nwkid, EPout, value, "Light", transitionMoveLevel)


value = int(_l * 254 // 100)
OnOff = "01"
self.log.logging( "Command", "Debug", "handle_color_mode_9998 Set Level: %s instead of Level: %s" % (value, value), nwkid)
actuator_setlevel(self, nwkid, EPout, value, "Light", transitionMoveLevel)
def handle_color_mode_tuya( self, nwkid, EPout, Hue_List, value):

self.log.logging("Command", "Debug", "handle_color_mode_tuya Hue_list: %s Value: %s" % (
Hue_List, value), nwkid)

transitionMoveLevel , transitionRGB , transitionMoveLevel , transitionHue , transitionTemp = get_all_transition_mode( self, nwkid)
_h, _s, _ = rgb_to_hsl((int(Hue_List["r"]), int(Hue_List["g"]), int(Hue_List["b"])))
saturation = _s * 100 # 0 > 100
saturation = int(saturation * 254 // 100)
hue = _h * 360 # 0 > 360
hue = int(hue * 254 // 360)

self.log.logging("Command", "Log", "handle_color_mode_tuya Set Hue X: %s Saturation: %s Value: %s" % (
hue, saturation, value), nwkid)
if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "TUYAColorControlRgbMode", return_default=None):
tuya_color_control_rgbMode( self, nwkid, "01")
tuya_Move_To_Hue_Saturation( self, nwkid, EPout, hue, saturation, transitionHue, value )

def actuator_identify(self, nwkid, ep, value=None):

Expand All @@ -351,4 +389,36 @@ def actuator_identify(self, nwkid, ep, value=None):
value = 0x00 # Flashing
color = 0x03 # Blue

zcl_identify_trigger_effect( self, nwkid, ep, "%02x" % value, "%02x" % color)
zcl_identify_trigger_effect( self, nwkid, ep, "%02x" % value, "%02x" % color)


def decode_color_capabilities(capabilities_value):
capabilities = {
"Hue and Saturation": 0b00000000_00000001,
"Enhanced Hue": 0b00000000_00000010,
"Color Loop": 0b00000000_00000100,
"XY Attributes": 0b00000000_00001000,
"Color Temperature": 0b00000000_00010000
}

return [
feature
for feature, bitmask in capabilities.items()
if capabilities_value & bitmask
]

def device_color_capabilities( self, nwkid, ep):
self.log.logging( "Command", "Debug", "device_color_capabilities %s %s" % (nwkid, ep), nwkid)
deviceHasNoColorCapabilities = get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "NoColorCapabilitie", return_default=None)
colorCapabilities = getAttributeValue( self, nwkid, ep, "0300", "400a")

self.log.logging( "Command", "Debug", "+ deviceHasColorCapabilities %s" % (deviceHasNoColorCapabilities), nwkid)
self.log.logging( "Command", "Debug", "+ colorCapabilities %s" % (colorCapabilities), nwkid)

if colorCapabilities is None and deviceHasNoColorCapabilities:
return []
if colorCapabilities is None or isinstance( colorCapabilities, str):
ReadAttributeRequest_0300_Color_Capabilities(self, nwkid)
return []

return decode_color_capabilities(colorCapabilities)
7 changes: 4 additions & 3 deletions Modules/basicOutputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@
from Zigbee.zclCommands import (zcl_attribute_discovery_request,
zcl_get_list_attribute_extended_infos,
zcl_identify_send, zcl_identify_trigger_effect,
zcl_read_attribute, zcl_write_attribute,
zcl_read_attribute, zcl_reset_device,
zcl_write_attribute,
zcl_write_attributeNoResponse)
from Zigbee.zdpCommands import (zdp_get_permit_joint_status,
zdp_IEEE_address_request,
zdp_management_leave_request,
zdp_management_network_update_request,
zdp_many_to_one_route_request,
zdp_permit_joining_request,
zdp_raw_nwk_update_request, zdp_reset_device)
zdp_raw_nwk_update_request)
from Zigbee.zdpRawCommands import (zdp_management_binding_table_request,
zdp_management_routing_table_request)

Expand Down Expand Up @@ -417,7 +418,7 @@ def reset_device(self, nwkid, epout):

self.log.logging("BasicOutput", "Debug", "reset_device - Send a Device Reset to %s/%s" % (nwkid, epout), nwkid)
#return send_zigatecmd_raw(self, "0050", "02" + nwkid + ZIGATE_EP + epout)
return zdp_reset_device(self, nwkid, ZIGATE_EP, epout)
return zcl_reset_device(self, nwkid, ZIGATE_EP, epout)


def leaveRequest(self, ShortAddr=None, IEEE=None, RemoveChild=0x00, Rejoin=0x00):
Expand Down
Loading

0 comments on commit ba1b776

Please sign in to comment.