Skip to content
Open
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
10 changes: 10 additions & 0 deletions drivers/SmartThings/zigbee-contact/fingerprints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,16 @@ zigbeeManufacturer:
manufacturer: Third Reality, Inc
model: 3RVS01031Z
deviceProfileName: thirdreality-multi-sensor
- id: "SONOFF/SNZB-04P"
deviceLabel: SONOFF Contact Sensor
manufacturer: eWeLink
model: SNZB-04P
deviceProfileName: contact-battery-tamper
- id: "SONOFF/SNZB-04PR2"
deviceLabel: SONOFF Contact Sensor
manufacturer: SONOFF
model: SNZB-04PR2
deviceProfileName: contact-battery-tamper
- id: "Aug. Winkhaus SE/FM.V.ZB"
deviceLabel: Funkkontakt FM.V.ZB
manufacturer: Aug. Winkhaus SE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: contact-battery-tamper
components:
- id: main
capabilities:
- id: contactSensor
version: 1
- id: battery
version: 1
- id: samplereturn62595.tamperStatus
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: ContactSensor
1 change: 0 additions & 1 deletion drivers/SmartThings/zigbee-contact/src/configurations.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ local devices = {
EWELINK_HEIMAN = {
FINGERPRINTS = {
{ mfr = "eWeLink", model = "DS01" },
{ mfr = "eWeLink", model = "SNZB-04P" },
{ mfr = "HEIMAN", model = "DoorSensor-N" }
},
CONFIGURATION = {
Expand Down
118 changes: 118 additions & 0 deletions drivers/SmartThings/zigbee-contact/src/sonoff/SNZB-04PR2/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
--[[
Description:
Version: 1.0
Autor: zehongwang
Date: 2025-08-22 16:47:37
LastEditors: zehongwang
LastEditTime:
--]]
local capabilities = require "st.capabilities"
local zcl_commands = require "st.zigbee.zcl.global_commands"
local cluster_base = require "st.zigbee.cluster_base"
local data_types = require "st.zigbee.data_types"
local sonoff_utils = require "sonoff/sonoff_utils"
local zcl_clusters = require "st.zigbee.zcl.clusters"
local battery_defaults = require "st.zigbee.defaults.battery_defaults"
local OccupancySensing = zcl_clusters.OccupancySensing
local log = require "log"
local zb_const = require "st.zigbee.constants"
local write_attr_response = require "st.zigbee.zcl.global_commands.write_attribute_response"
local data_types = require "st.zigbee.data_types"
local Status = (require "st.zigbee.zcl.types").ZclStatus
local defaults = require "st.zigbee.defaults"
local ZigbeeDriver = require "st.zigbee"
local IASZone = (require "st.zigbee.zcl.clusters").IASZone


local tamper = capabilities["samplereturn62595.tamperStatus"]


local PREF_TAMPER_INSTALL = 0
local PREF_TAMPER_REMOVE = 1

local FINGERPRINTS = {
{ mfr = "SONOFF", model = "SNZB-04PR2" }
}

local function spilt_attr_handler(driver, device, value, zb_rx)
log.debug("<<< Tamper Value >>>",value.value)
local raw_value = value.value
if raw_value == PREF_TAMPER_INSTALL then
device:emit_event(tamper.tamperProof.Normal())
log.debug("<<< -Tamper Value- >>>",value.value)
elseif raw_value == PREF_TAMPER_REMOVE then
device:emit_event(tamper.tamperProof.Tampered())
log.debug("<<< -Tamper Value- >>>",value.value)
end
end

-- local function contact_status_handler(self, device, value, zb_rx)
-- log.debug("<<< ZoneStatus Value >>>",value.value)
-- if value.value == 1 or value.value == true then
-- device:emit_event(capabilities.contactSensor.contact.open())
-- log.debug("<<< -ZoneStatus Value- >>>",value.value)
-- elseif value.value == 0 or value.value == false then
-- device:emit_event(capabilities.contactSensor.contact.closed())
-- log.debug("<<< -ZoneStatus Value- >>>",value.value)
-- end
-- end
local function contact_status_handler(driver, device, zb_rx)
local zone_status_value = zb_rx.body.zcl_body.zone_status.value
log.debug("<<< ZoneStatus Value >>>", zone_status_value)

if zone_status_value ~= nil then
local contact_bit = zone_status_value & 0x0001
if contact_bit == 0x0001 then
device:emit_event(capabilities.contactSensor.contact.open())
log.debug("<<< -Contact OPEN - >>>")
else
device:emit_event(capabilities.contactSensor.contact.closed())
log.debug("<<< -Contact CLOSED - >>>")
end
else
log.warn("Zone status value is nil")
end
end



local function added_handler(self, device)
--update UI
device:emit_event(tamper.tamperProof.Normal())
end

local function device_init(driver, device)
--do notthing
end

local sonoff_04PR2_contact_handler = {
NAME = "Sonoff contact Handler",
supported_capabilities = {
capabilities.battery,
capabilities.contact
},
lifecycle_handlers = {
init = device_init,
added = added_handler
},
zigbee_handlers = {
attr = {
[sonoff_utils.SONOFF_PRIVITE_CLUSTER_ID] = {
[sonoff_utils.SONOFF_SPILT_ATTRIBUTE_ID] = spilt_attr_handler
}
},
cluster = {
[IASZone.ID] = {
[IASZone.client.commands.ZoneStatusChangeNotification.ID] = contact_status_handler
}
}
},
can_handle = function(opts, driver, device, ...)
return device:get_model() == "SNZB-04PR2"
end
}

-- return sonoff_04PR2_contact_handler
defaults.register_for_default_handlers(sonoff_04PR2_contact_handler, sonoff_04PR2_contact_handler.supported_capabilities)
local zigbee_button = ZigbeeDriver("sonoff_04PR2_contact_handler", sonoff_04PR2_contact_handler)
zigbee_button:run()
139 changes: 139 additions & 0 deletions drivers/SmartThings/zigbee-contact/src/sonoff/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
--[[
Description:
Version: 2.0
Autor: liangjia
Date: 2024-04-25 13:38:25
LastEditors: liangjia
LastEditTime: 2024-04-25 13:53:04
--]]
--[[
Description:
Version: 2.0
Autor: liangjia
Date: 2024-04-25 13:38:25
LastEditors: liangjia
LastEditTime: 2024-04-25 13:47:42
--]]
--[[
Description:
Version: 2.0
Autor: liangjia
Date: 2024-01-19 18:05:31
LastEditors: liangjia
LastEditTime: 2024-01-20 10:41:41
--]]
local capabilities = require "st.capabilities"
local zcl_commands = require "st.zigbee.zcl.global_commands"
local cluster_base = require "st.zigbee.cluster_base"
local data_types = require "st.zigbee.data_types"
local sonoff_utils = require "sonoff/sonoff_utils"
local zcl_clusters = require "st.zigbee.zcl.clusters"
local battery_defaults = require "st.zigbee.defaults.battery_defaults"
local OccupancySensing = zcl_clusters.OccupancySensing
local log = require "log"
local zb_const = require "st.zigbee.constants"
local write_attr_response = require "st.zigbee.zcl.global_commands.write_attribute_response"
local data_types = require "st.zigbee.data_types"
local Status = (require "st.zigbee.zcl.types").ZclStatus
local IASZone = (require "st.zigbee.zcl.clusters").IASZone


local tamper = capabilities["samplereturn62595.tamperStatus"]


local PREF_TAMPER_INSTALL = 0
local PREF_TAMPER_REMOVE = 1

local FINGERPRINTS = {
{ mfr = "SONOFF", model = "SNZB-04P" },
{ mfr = "SONOFF", model = "SNZB-04PR2" }
}

local is_sonoff_products = function(opts, driver, device)
for _, fingerprint in ipairs(FINGERPRINTS) do
if device:get_model() == fingerprint.model then
return true
end
end
return false
end

local function spilt_attr_handler(driver, device, value, zb_rx)
log.debug("<<< Tamper Value >>>",value.value)
local raw_value = value.value
if raw_value == PREF_TAMPER_INSTALL then
device:emit_event(tamper.tamperProof.Normal())
log.debug("<<< -Tamper Value- >>>",value.value)
elseif raw_value == PREF_TAMPER_REMOVE then
device:emit_event(tamper.tamperProof.Tampered())
log.debug("<<< -Tamper Value- >>>",value.value)
end
end

-- local function contact_status_handler(self, device, value, zb_rx)
-- log.debug("<<< ZoneStatus Value >>>",value.value)
-- if value.value == 1 or value.value == true then
-- device:emit_event(capabilities.contactSensor.contact.open())
-- log.debug("<<< -ZoneStatus Value- >>>",value.value)
-- elseif value.value == 0 or value.value == false then
-- device:emit_event(capabilities.contactSensor.contact.closed())
-- log.debug("<<< -ZoneStatus Value- >>>",value.value)
-- end
-- end
local function contact_status_handler(driver, device, zb_rx)
local zone_status_value = zb_rx.body.zcl_body.zone_status.value
log.debug("<<< ZoneStatus Value >>>", zone_status_value)

if zone_status_value ~= nil then
local contact_bit = zone_status_value & 0x0001
if contact_bit == 0x0001 then
device:emit_event(capabilities.contactSensor.contact.open())
log.debug("<<< -Contact OPEN - >>>")
else
device:emit_event(capabilities.contactSensor.contact.closed())
log.debug("<<< -Contact CLOSED - >>>")
end
else
log.warn("Zone status value is nil")
end
end



local function added_handler(self, device)
--update UI
device:emit_event(tamper.tamperProof.Normal())
end

local function device_init(driver, device)
--do notthing
end

local sonoff_contact_handler = {
NAME = "Sonoff contact Handler",
lifecycle_handlers = {
init = device_init,
added = added_handler
},
zigbee_handlers = {
attr = {
[sonoff_utils.SONOFF_PRIVITE_CLUSTER_ID] = {
[sonoff_utils.SONOFF_SPILT_ATTRIBUTE_ID] = spilt_attr_handler
}
},
cluster = {
[IASZone.ID] = {
[IASZone.client.commands.ZoneStatusChangeNotification.ID] = contact_status_handler
}
}
},
sub_drivers = {
require("sonoff/SNZB-04PR2")
},
can_handle = is_sonoff_products
-- can_handle = function(opts, driver, device, ...)
-- return device:get_model() == "SNZB-04P"
-- end
}

return sonoff_contact_handler
79 changes: 79 additions & 0 deletions drivers/SmartThings/zigbee-contact/src/sonoff/sonoff_utils.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
--[[
Description:
Version: 2.0
Autor: liangjia
Date: 2024-01-24 12:00:32
LastEditors: liangjia
LastEditTime: 2024-02-02 15:20:58
--]]
--[[
Description:
Version: 2.0
Autor: liangjia
Date: 2024-01-19 18:05:31
LastEditors: liangjia
LastEditTime: 2024-01-20 13:51:20
--]]
--[[
Description:
Version: 2.0
Autor: liangjia
Date: 2024-01-19 15:39:47
LastEditors: liangjia
LastEditTime: 2024-01-19 16:18:46
--]]
local capabilities = require "st.capabilities"
local log = require "log"
local zb_const = require "st.zigbee.constants"

local OCCUPANCY_CLUSTER_ID = 0x0406
local OCCUPANCY_UTO_ATTRIBUTE_ID = 0x0020
local MFG_CODE = 0x1286
local SONOFF_PRIVITE_CLUSTER_ID = 0xFC11
local SONOFF_ILLUMINATION_LEVEL_ATTRIBUTE_ID = 0x2001
local SONOFF_SPILT_ATTRIBUTE_ID = 0x2000

local sonoff_utils = {}

local PREF_FREQUENCY_KEY = "prefFrequency"
local PREF_FREQUENCY_VALUE_DEFAULT = 60


local PREF_SENSITIVITY_KEY = "sensitivity"
local PREF_SENSITIVITY_VALUE_DEFAULT = 2

local PREF_CHANGED_KEY = "prefChangedKey"
local PREF_CHANGED_VALUE = "prefChangedValue"

local function motion_detected(device)
device:emit_event(capabilities.motionSensor.motion.active())
end

local function get_pref_changed_field(device)
local key = device:get_field(PREF_CHANGED_KEY) or ''
local value = device:get_field(PREF_CHANGED_VALUE) or 0
return key, value
end

local function set_pref_changed_field(device, key, value)
log.debug("set_pref_changed_field---->value:",value)
device:set_field(PREF_CHANGED_KEY, key)
device:set_field(PREF_CHANGED_VALUE, value)
end

sonoff_utils.OCCUPANCY_CLUSTER_ID = OCCUPANCY_CLUSTER_ID
sonoff_utils.OCCUPANCY_UTO_ATTRIBUTE_ID = OCCUPANCY_UTO_ATTRIBUTE_ID
sonoff_utils.MFG_CODE = MFG_CODE

sonoff_utils.PREF_FREQUENCY_KEY = PREF_FREQUENCY_KEY
sonoff_utils.PREF_FREQUENCY_VALUE_DEFAULT = PREF_FREQUENCY_VALUE_DEFAULT
sonoff_utils.PREF_SENSITIVITY_KEY = PREF_SENSITIVITY_KEY
sonoff_utils.PREF_SENSITIVITY_VALUE_DEFAULT = PREF_SENSITIVITY_VALUE_DEFAULT
sonoff_utils.SONOFF_PRIVITE_CLUSTER_ID = SONOFF_PRIVITE_CLUSTER_ID
sonoff_utils.SONOFF_ILLUMINATION_LEVEL_ATTRIBUTE_ID = SONOFF_ILLUMINATION_LEVEL_ATTRIBUTE_ID
sonoff_utils.SONOFF_SPILT_ATTRIBUTE_ID = SONOFF_SPILT_ATTRIBUTE_ID
sonoff_utils.motion_detected = motion_detected
sonoff_utils.get_pref_changed_field = get_pref_changed_field
sonoff_utils.set_pref_changed_field = set_pref_changed_field

return sonoff_utils