Skip to content

Commit

Permalink
Merge branch 'wip-stable7.1.010' into stable7
Browse files Browse the repository at this point in the history
  • Loading branch information
pipiche38 committed Mar 16, 2024
2 parents b270366 + 7c5700a commit 33f862a
Show file tree
Hide file tree
Showing 15 changed files with 192 additions and 98 deletions.
69 changes: 34 additions & 35 deletions Classes/IAS.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,23 @@


STROBE_LEVEL = {"Low": 0x00, "Medium": 0x01}

SIRENE_MODE = ("both", "siren", "strobe", "stop")

WARNING_DEVICE_MODES = {
"both": (0x01, 0x01),
"siren": (0x00, 0x01),
"stop": (0x00, 0x00),
"strobe": (0x01, 0x00)
}

SIREN_MODES = {
"both": (STROBE_LEVEL["Low"], 0x02, 0x01),
"siren": (0x00, 0x00, 0x02),
"stop": (0x00, 0x00, 0x00),
"strobe": (STROBE_LEVEL["Low"], 0x01, 0x00)
}

strobe_mode = 0x00


Expand Down Expand Up @@ -309,14 +325,18 @@ def write_IAS_WD_Squawk(self, NwkId, ep, SquawkMode):
zcl_ias_wd_command_squawk(self, ZIGATE_EP, ep, NwkId, squawk_mode, strobe, squawk_level, ackIsDisabled=False)

def warningMode(self, NwkId, ep, mode="both", siren_level=0x01, warning_duration=0x01, strobe_duty=0x32, strobe_level=0x00):

self.logging("Debug", f"warningMode {mode} {siren_level} {warning_duration} {strobe_duty} {strobe_level}")

if mode in ( "siren", "both") and "Param" in self.ListOfDevices[ NwkId ] and "sirenLevel" in self.ListOfDevices[ NwkId ]["Param"]:
siren_level = self.ListOfDevices[ NwkId ]["Param"]["sirenLevel"]
if mode in ( "strobe", "both") and "Param" in self.ListOfDevices[ NwkId ] and "sirenLevel" in self.ListOfDevices[ NwkId ]["Param"]:

if mode in ( "strobe", "both") and "Param" in self.ListOfDevices[ NwkId ] and "strobeDutyCycle" in self.ListOfDevices[ NwkId ]["Param"]:
strobe_duty = self.ListOfDevices[ NwkId ]["Param"]["strobeDutyCycle"]

strobe_mode, warning_mode, strobe_level, warning_duration = ias_sirene_mode( self, NwkId , mode , warning_duration)
self.logging("Debug", f"warningMode - Mode: {bin(warning_mode)}, Duration: {warning_duration}, Duty: {strobe_duty}, Level: {strobe_level}")

self.logging("Debug", f"warningMode - Mode: {warning_mode}, Duration: {warning_duration}, Duty: {strobe_duty}, Level: {strobe_level}")

zcl_ias_wd_command_start_warning(self, ZIGATE_EP, ep, NwkId, warning_mode, strobe_mode, siren_level, warning_duration, strobe_duty, strobe_level, groupaddrmode=False, ackIsDisabled=False)

def siren_both(self, NwkId, ep):
Expand Down Expand Up @@ -358,42 +378,19 @@ def iaswd_develco_warning(self, NwkId, ep, sirenonoff):
raw_APS_request(self, NwkId, ep, Cluster, "0104", payload, zigpyzqn=sqn, zigate_ep=ZIGATE_EP, ackIsDisabled=False)
return sqn

def ias_sensitivity(self, nwkid, sensitivity):

if sensitivity not in ( 0, 1, 2):
return
write_attribute(self, nwkid, ZIGATE_EP, "01", "0500", "0000", "00", "0013", "20", "%02x" %sensitivity, ackIsDisabled=False)



def ias_sirene_mode( self, NwkId , mode, warning_duration ):
self.logging("Debug", f"ias_sirene_mode - {NwkId} Mode: {mode}, Duration: {warning_duration}")

strobe_mode = warning_mode = strobe_level = 0x00

if self.ListOfDevices[NwkId]["Model"] == "WarningDevice":
if mode == "both":
strobe_mode = 0x01
warning_mode = 0x01
elif mode == "siren":
warning_mode = 0x01
elif mode == "stop":
strobe_mode = 0x00
warning_mode = 0x00
elif mode == "strobe":
strobe_mode = 0x01
warning_mode = 0x00
strobe_mode, warning_mode = WARNING_DEVICE_MODES.get(mode, (0x00, 0x00))

elif mode in SIRENE_MODE:
if mode == "both":
strobe_level = STROBE_LEVEL["Low"]
strobe_mode = 0x02
warning_mode = 0x01
elif mode == "siren":
warning_mode = 0x02
elif mode == "stop":
strobe_mode = 0x00
warning_mode = 0x00
elif mode == "strobe":
strobe_level = STROBE_LEVEL["Low"]
strobe_mode = 0x01
warning_mode = 0x00
strobe_level, strobe_mode, warning_mode = SIREN_MODES.get(mode, (0x00, 0x00, 0x00))

self.logging("Debug", f"ias_sirene_mode - before checking param {NwkId} warning_mode: {warning_mode}, strobe_mode: {strobe_mode}, strobe_level: {strobe_level}")
if "Param" in self.ListOfDevices[NwkId]:
if "alarmDuration" in self.ListOfDevices[NwkId]["Param"]:
warning_duration = int(self.ListOfDevices[NwkId]["Param"]["alarmDuration"])
Expand All @@ -405,7 +402,9 @@ def ias_sirene_mode( self, NwkId , mode, warning_duration ):
warning_mode = int(self.ListOfDevices[NwkId]["Param"]["alarmSirenCode"])

if mode in ("strobe", "both") and "strobeLevel" in self.ListOfDevices[ NwkId ]["Param"]:
strobe_level = self.ListOfDevices[ NwkId ]["Param"]["strobeLevel"]
strobe_level = self.ListOfDevices[ NwkId ]["Param"]["strobeLevel"]

self.logging("Debug", f"ias_sirene_mode - after checking param {NwkId} warning_mode: {warning_mode}, strobe_mode: {strobe_mode}, strobe_level: {strobe_level}, warning_duration: {warning_duration}")

return strobe_mode, warning_mode, strobe_level, warning_duration

Expand Down
3 changes: 0 additions & 3 deletions Classes/LoggingManagement.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ def __init__(self, pluginconf, PluginHealth, HardwareID, ListOfDevices, permitTo
configure_zigpy_zigate_loggers("warning")
configure_zigpy_deconz_loggers("warning")




self.zigpy_login()

start_logging_thread(self)
Expand Down
1 change: 1 addition & 0 deletions Classes/PluginConf.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@
"coordinatorCmd": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True },
"enablePluginLogging": { "type": "bool", "default": 1, "current": None, "restart": 1, "hidden": False, "Advanced": False },
"inRawAPS": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True },
"iasSettings": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": True },
"logDeviceUpdate": { "type": "bool", "default": 1, "current": None, "restart": 0, "hidden": False, "Advanced": False },
"logFORMAT": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": True, "Advanced": True },
"logThreadName": { "type": "bool", "default": 0, "current": None, "restart": 0, "hidden": False, "Advanced": False },
Expand Down
25 changes: 24 additions & 1 deletion DevicesModules/custom_sonoff.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@
# SPDX-License-Identifier: GPL-3.0 license

from Modules.basicOutputs import write_attribute
from Modules.readAttributes import ReadAttributeRequest_0406_0022
from Modules.tools import get_device_config_param
from Modules.zigateConsts import ZIGATE_EP

SONOFF_MAUFACTURER_NAME = "SONOFF"
SONOFF_MANUFACTURER_ID = "1286"
SONOFF_CLUSTER_ID = "fc11"
SONOFF_ILLUMINATION_ATTRIBUTE = "2001"
SONOFF_MAX_TEMP = "0003"
SONOFF_MIN_TEMP = "0004"
SONOFF_MAX_HUMI = "0005"
SONOFF_MIN_HUMI = "0006"


def is_sonoff_device(self, nwkid):
Expand All @@ -33,7 +37,26 @@ def sonoff_open_window_detection(self, nwkid, detection):
self.log.logging("Sonoff", "Debug", "sonoff_child_lock - Nwkid: %s Mode: %s" %(nwkid, detection))
write_attribute(self, nwkid, ZIGATE_EP, "01", SONOFF_CLUSTER_ID, SONOFF_MANUFACTURER_ID, "01", "6000", "10", "%02x" %detection, ackIsDisabled=False)


def sonoff_temp_humi_ranges(self, nwkid, value):
self.log.logging("Sonoff", "Debug", "sonoff_temp_humi_ranges - Nwkid: %s Mode: %s" %(nwkid, value))
temp_max = get_device_config_param(self, nwkid, "SONOFF_TEMP_MAX")
temp_min = get_device_config_param(self, nwkid, "SONOFF_TEMP_MIN")
humi_max = get_device_config_param(self, nwkid, "SONOFF_HUMI_MAX")
humi_min = get_device_config_param(self, nwkid, "SONOFF_HUMI_MIN")

write_attribute(self, nwkid, ZIGATE_EP, "01", SONOFF_CLUSTER_ID, SONOFF_MANUFACTURER_ID, "01", SONOFF_MAX_TEMP, "29", "%04x" %temp_max, ackIsDisabled=False)
write_attribute(self, nwkid, ZIGATE_EP, "01", SONOFF_CLUSTER_ID, SONOFF_MANUFACTURER_ID, "01", SONOFF_MIN_TEMP, "29", "%04x" %temp_min, ackIsDisabled=False)
write_attribute(self, nwkid, ZIGATE_EP, "01", SONOFF_CLUSTER_ID, SONOFF_MANUFACTURER_ID, "01", SONOFF_MAX_HUMI, "21", "%04x" %humi_max, ackIsDisabled=False)
write_attribute(self, nwkid, ZIGATE_EP, "01", SONOFF_CLUSTER_ID, SONOFF_MANUFACTURER_ID, "01", SONOFF_MIN_HUMI, "21", "%04x" %humi_min, ackIsDisabled=False)



SONOFF_DEVICE_PARAMETERS = {
"SonOffTRVChildLock": sonoff_child_lock,
"SonOffTRVWindowDectection": sonoff_open_window_detection,
"SONOFF_TEMP_MAX": sonoff_temp_humi_ranges,
"SONOFF_TEMP_MIN": sonoff_temp_humi_ranges,
"SONOFF_HUMI_MAX": sonoff_temp_humi_ranges,
"SONOFF_HUMI_MIN": sonoff_temp_humi_ranges
}
18 changes: 14 additions & 4 deletions Modules/actuators.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ def get_all_transition_mode( self, Nwkid):
transitionHue = "%04x" % int(self.ListOfDevices[Nwkid]["Param"]["moveToHueSatu"])
return transitionMoveLevel , transitionRGB , transitionMoveLevel ,transitionHue , transitionTemp


def actuator_setcolor(self, nwkid, EPout, value, Color):

Hue_List = json.loads(Color)
Expand Down Expand Up @@ -287,12 +288,17 @@ def handle_color_mode_2(self, nwkid, EPout, Hue_List):
# t is 0 > 255
TempKelvin = int(((255 - int(Hue_List["t"])) * (6500 - 1700) / 255) + 1700)
TempMired = 1000000 // TempKelvin

if get_deviceconf_parameter_value(self, self.ListOfDevices[nwkid]["Model"], "WSRangeForTradfri", return_default=False):
# Looks like Tradfri might have some limitation
self.log.logging( "Command", "Debug", "handle_color_mode_2 bring TempMired into the Tradfri Range 250,454", nwkid )
TempMired = max(250, min(TempMired, 454))

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"])))
Expand All @@ -305,7 +311,8 @@ def handle_color_mode_3(self, nwkid, EPout, Hue_List):
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 ):
# Gledopto GL_008
# Color: {"b":43,"cw":27,"g":255,"m":4,"r":44,"t":227,"ww":215}
Expand Down Expand Up @@ -335,7 +342,8 @@ def handle_color_mode_4(self, nwkid, EPout, Hue_List ):
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, 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"])))
Expand Down Expand Up @@ -375,6 +383,7 @@ def handle_color_mode_tuya( self, nwkid, EPout, Hue_List, value):
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):

if value is None:
Expand Down Expand Up @@ -417,6 +426,7 @@ def decode_color_capabilities(capabilities_value):
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)
Expand Down
19 changes: 13 additions & 6 deletions Modules/domoCreate.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,17 @@ def CreateDomoDevice(self, Devices, NWKID):

t = update_widget_type_if_possible( self, NWKID, t)

if t in ("Aqara", "XCube"):
# We expect Only 1 Type, so after the creation of the 2 Widgets break
create_xcube_widgets(self, Devices, NWKID, DeviceID_IEEE, Ep, t)
break

if create_native_widget( self, Devices, NWKID, DeviceID_IEEE, Ep, t):
continue

if create_switch_selector_widget( self, Devices, NWKID, DeviceID_IEEE, Ep, t):
continue

if t in ("Aqara", "XCube") and create_xcube_widgets(self, Devices, NWKID, DeviceID_IEEE, Ep, t):
continue

# for Ep
update_device_type( self, NWKID, GlobalType )
Expand Down Expand Up @@ -355,27 +358,31 @@ def create_xcube_widgets(self, Devices, NWKID, DeviceID_IEEE, Ep, t):
# usage later on is based on that assumption
#
# Xiaomi Magic Cube
self.log.logging( "WidgetCreation", "Debug", f"create_xcube_widgets - Xiaomi Magic Cube {NWKID} {DeviceID_IEEE} {Ep} {t}")

self.ListOfDevices[NWKID]["Status"] = "inDB"
# Create the XCube Widget
Options = createSwitchSelector(self, 10, DeviceType=t, OffHidden=True, SelectorStyle=1)
unit = FreeUnit(self, Devices, nbunit_=2) # Look for 2 consecutive slots
unit = FreeUnit(self, Devices, DeviceID_IEEE, nbunit_=2) # Look for 2 consecutive slots
myDev = Domoticz.Device( DeviceID=str(DeviceID_IEEE), Name=deviceName(self, NWKID, t, DeviceID_IEEE, Ep), Unit=unit, Type=244, Subtype=62, Switchtype=18, Options=Options, )
myDev.Create()
ID = myDev.ID
if myDev.ID == -1:
self.ListOfDevices[NWKID]["Status"] = "failDB"
Domoticz.Error("Domoticz widget creation failed. %s" % (str(myDev)))
self.log.logging( "WidgetCreation", "Error", "Domoticz widget creation failed. %s" % (str(myDev)))
else:
self.log.logging( "WidgetCreation", "Debug", f"create_xcube_widgets - widgetID {ID} for '{t}'")
self.ListOfDevices[NWKID]["Ep"][Ep]["ClusterType"][str(ID)] = t

# Create the Status (Text) Widget to report Rotation angle
unit += 1
myDev = Domoticz.Device( DeviceID=str(DeviceID_IEEE), Name=deviceName(self, NWKID, t, DeviceID_IEEE, Ep), Unit=unit, Type=243, Subtype=19, Switchtype=0, )
myDev = Domoticz.Device( DeviceID=str(DeviceID_IEEE), Name=deviceName(self, NWKID, "Text", DeviceID_IEEE, Ep), Unit=unit, Type=243, Subtype=19, Switchtype=0, )
myDev.Create()
ID = myDev.ID
if myDev.ID == -1:
Domoticz.Error("Domoticz widget creation failed. %s" % (str(myDev)))
self.log.logging( "WidgetCreation", "Error", "Domoticz widget creation failed. %s" % (str(myDev)))
else:
self.log.logging( "WidgetCreation", "Debug", f"create_xcube_widgets - widgetID {ID} for 'Text'")
self.ListOfDevices[NWKID]["Ep"][Ep]["ClusterType"][str(ID)] = "Text"


Expand Down
1 change: 1 addition & 0 deletions Modules/domoTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ def UpdateDevice_v2(self, Devices, Unit, nValue, sValue, BatteryLvl, SignalLvl,
domo_update_api(self, Devices, DeviceID_, Unit, nValue, sValue, SignalLevel=SignalLvl, BatteryLevel=BatteryLvl, TimedOut=0, Color=Color_,)

if self.pluginconf.pluginConf["logDeviceUpdate"]:
self.log.logging( "Widget", "Log", "UpdateDevice - (%15s) %s:%s" % (Devices[Unit].Name, nValue, sValue))
domoticz_log_api( "UpdateDevice - (%15s) %s:%s" % (Devices[Unit].Name, nValue, sValue))
self.log.logging( "Widget", "Debug", "---> [Unit: %s] %s:%s:%s %s:%s %s (%15s)" % (
Unit, nValue, sValue, Color_, BatteryLvl, SignalLvl, ForceUpdate_, Devices[Unit].Name), self.IEEE2NWK[Devices[Unit].DeviceID], )
Expand Down
49 changes: 45 additions & 4 deletions Modules/ias_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,36 @@

IAS_CLUSTER_ID = "0500"


ONOFF_CONFIG_SET = {
"IAS_CIE_Address": ( "0010", "f0"),
"ZoneID": ( "0011", "20"),
"NumberOfZoneSensitivityLevelsSupported": ( "0012", "20"),
"CurrentZoneSensitivityLevel": ( "0013", "20")
}

IASWD_CLUSTER_ID = "0502"

IASWD_CONFIG_SET = {
"IAS_WD_MAXIMUM_DURATION": ( "0000", "21"),
}

def ias_CurrentZoneSensitivityLevel(self, nwkid, value):
self.log.logging( "iasSettings", "Debug", f"ias_CurrentZoneSensitivityLevel for {nwkid} - sensitivity: {value}", nwkid )
ListOfEp = getListOfEpForCluster(self, nwkid, IAS_CLUSTER_ID)
for ep in ListOfEp:
ias_CurrentZoneSensitivityLevel_by_ep(self, nwkid, ep, value)

def ias_CurrentZoneSensitivityLevel(self, nwkid, ep, value):

def ias_CurrentZoneSensitivityLevel_by_ep(self, nwkid, ep, value):
""" Allows an IAS Zone client to query and configure the IAS Zone server’s sensitivity level. """

# The default value 0x00 is the device’s default sensitivity level as configured by the manufacturer. It MAY
# correspond to the same sensitivity as another value in the NumberOfZoneSensitivityLevelsSupported, but this
# is the default sensitivity to be used if the CurrentZoneSensitivityLevel attribute is not otherwise configured
# by an IAS Zone client.

self.log.logging( "onoffSettings", "Debug", f"ias_CurrentZoneSensitivityLevel for {nwkid}/{ep} - value: {value}", nwkid )
self.log.logging( "iasSettings", "Debug", f"ias_CurrentZoneSensitivityLevel for {nwkid}/{ep} - value: {value}", nwkid )
write_attribute(
self,
nwkid,
Expand All @@ -48,6 +61,34 @@ def ias_CurrentZoneSensitivityLevel(self, nwkid, ep, value):
ackIsDisabled=False, )



def ias_maximum_duration(self, nwkid, maximum_duration=60):

self.log.logging( "iasSettings", "Debug", f"ias_maximum_duration for {nwkid} - max_duration: {maximum_duration}", nwkid )

ListOfEp = getListOfEpForCluster(self, nwkid, IAS_CLUSTER_ID)
for ep in ListOfEp:
ias_CurrentZoneSensitivityLevel_by_ep(self, nwkid, ep, maximum_duration)


def ias_maximum_duration_by_ep(self, nwkid, ep, maximum_duration=60):
self.log.logging( "iasSettings", "Debug", f"ias_maximum_duration_by_ep for {nwkid} - max_duration: {maximum_duration}", nwkid )

write_attribute(
self,
nwkid,
ZIGATE_EP,
ep,
IASWD_CLUSTER_ID,
"0000",
"00",
IASWD_CONFIG_SET[ "IAS_WD_MAXIMUM_DURATION"][0],
IASWD_CONFIG_SET[ "IAS_WD_MAXIMUM_DURATION"][1],
"%04x" %maximum_duration,
ackIsDisabled=False, )

IAS_DEVICE_PARAMETERS = {
"CurrentZoneSensitivityLevel": ias_CurrentZoneSensitivityLevel
}
"CurrentZoneSensitivityLevel": ias_CurrentZoneSensitivityLevel,
"IASsensitivity": ias_CurrentZoneSensitivityLevel,
"SireneMaxAlarmDuration": ias_maximum_duration
}
Loading

0 comments on commit 33f862a

Please sign in to comment.