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
22 changes: 20 additions & 2 deletions drivers/SmartThings/zigbee-valve/fingerprints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,23 @@ zigbeeManufacturer :
manufacturer: Compacta
model: ZBVC1(1023A)
deviceProfileName: valve-battery-powerSource


- id: SONOFF/SWV-ZFE
deviceLabel: SONOFF Water Valve
manufacturer: SONOFF
model: SWV-ZFE
deviceProfileName: sonoff-irrigation
- id: SONOFF/SWV-ZFU
deviceLabel: SONOFF Water Valve
manufacturer: SONOFF
model: SWV-ZFU
deviceProfileName: sonoff-irrigation
- id: SONOFF/SWV-ZNE
deviceLabel: SONOFF Water Valve
manufacturer: SONOFF
model: SWV-ZNE
deviceProfileName: sonoff-irrigation
- id: SONOFF/SWV-ZNU
deviceLabel: SONOFF Water Valve
manufacturer: SONOFF
model: SWV-ZNU
deviceProfileName: sonoff-irrigation
14 changes: 14 additions & 0 deletions drivers/SmartThings/zigbee-valve/profiles/valve-battery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: valve-battery
components:
- id: main
capabilities:
- id: valve
version: 1
- id: battery
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories :
- name: WaterValve
35 changes: 29 additions & 6 deletions drivers/SmartThings/zigbee-valve/src/init.lua
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
-- Copyright 2022 SmartThings, Inc.
-- Licensed under the Apache License, Version 2.0

-- Copyright 2022 SmartThings
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

local ZigbeeDriver = require "st.zigbee"
local defaults = require "st.zigbee.defaults"

--ZCL
local zcl_clusters = require "st.zigbee.zcl.clusters"
local Basic = zcl_clusters.Basic
local PowerConfiguration = zcl_clusters.PowerConfiguration
--Capability
local capabilities = require "st.capabilities"
local battery = capabilities.battery
Expand All @@ -27,6 +38,17 @@ local zigbee_valve_driver_template = {
refresh
},
cluster_configurations = {
[battery.ID] = {
{
cluster = PowerConfiguration.ID,
attribute = PowerConfiguration.attributes.BatteryPercentageRemaining.ID,
minimum_interval = 300,
maximum_interval = 900,
data_type = PowerConfiguration.attributes.BatteryPercentageRemaining.base_type,
reportable_change = 2,
configurable = true
}
},
[powerSource.ID] = {
{
cluster = Basic.ID,
Expand All @@ -41,9 +63,10 @@ local zigbee_valve_driver_template = {
lifecycle_handlers = {
added = device_added
},
sub_drivers = require("sub_drivers"),
health_check = false,
shared_device_thread_enabled = true,
sub_drivers = {
require("sinope"),
require("sonoff")
}
}

defaults.register_for_default_handlers(zigbee_valve_driver_template, zigbee_valve_driver_template.supported_capabilities)
Expand Down
118 changes: 118 additions & 0 deletions drivers/SmartThings/zigbee-valve/src/sonoff/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
-- Copyright 2026 SmartThings, Inc.
-- Licensed under the Apache License, Version 2.0

local capabilities = require "st.capabilities"
local zcl_clusters = require "st.zigbee.zcl.clusters"
local OnOff = zcl_clusters.OnOff
local PowerConfiguration = zcl_clusters.PowerConfiguration
local utils = require "st.utils"

-- Battery Polling Interval (seconds): SWV1C is a battery sleep device, polling every 2 hours
local BATTERY_POLL_INTERVAL = 7200

-- SWV1C Fingerprint list
local FINGERPRINTS = {
{ mfr = "SONOFF", model = "SWV-ZFU" },
{ mfr = "SONOFF", model = "SWV-ZFE" },
{ mfr = "SONOFF", model = "SWV-ZNU" },
{ mfr = "SONOFF", model = "SWV-ZNE" }
}

--- OnOff Property Reporting Handler → Valve Capability Point Event
--- It must be handled explicitly because the child driver defines capability_handlers.
--- The default OnOff→valve mapping from the parent driver will be skipped (only OnOff→switch remains)
--- @param driver table Driver instance
--- @param device table Device instance
--- @param value table Zigbee attribute value
local function onoff_attr_handler(driver, device, value)
local is_on = value.value ~= false and value.value ~= 0
if is_on then
device:emit_event(capabilities.valve.valve.open())
else
device:emit_event(capabilities.valve.valve.closed())
end
end

--- Battery Percentage Attribute Handler
--- Zigbee BatteryPercentageRemaining range 0-200 (0%-100%), needs to be divided by 2
--- @param driver table Driver instance
--- @param device table Device instance
--- @param value table Zigbee attribute value
local function battery_percentage_handler(driver, device, value)
local raw = value.value
local percent = utils.round(raw / 2)
device:emit_event(capabilities.battery.battery(percent))
end

--- Lifecycle initialization handler
--- Ensures battery data is available by periodically actively reading BatteryPercentageRemaining
--- @param driver table Driver instance
--- @param device table Device instance
local function device_init(driver, device)
device.thread:call_on_schedule(
BATTERY_POLL_INTERVAL,
function()
device:send(PowerConfiguration.attributes.BatteryPercentageRemaining:read(device))
end
)
end

--- valve.open ability handler
--- @param driver table driver instance
--- @param device table device instance
--- @param command table ability command
local function valve_open_handler(driver, device, command)
device:send(OnOff.server.commands.On(device))
device:send(OnOff.attributes.OnOff:read(device))
end

--- valve.close capability handler
--- @param driver table driver instance
--- @param device table device instance
--- @param command table capability command
local function valve_close_handler(driver, device, command)
device:send(OnOff.server.commands.Off(device))
device:send(OnOff.attributes.OnOff:read(device))
end

--- Device Matching Check
--- @param opts table Options
--- @param driver table Driver instance
--- @param device table Device instance
--- @return boolean Whether this sub-driver takes over
local function is_sonoff_valve(opts, driver, device)
for _, fingerprint in ipairs(FINGERPRINTS) do
if device:get_manufacturer() == fingerprint.mfr and device:get_model() == fingerprint.model then
return true
end
end
return false
end

local sonoff_valve_handler = {
NAME = "SONOFF Water Valve Handler",
lifecycle_handlers = {
init = device_init
},
capability_handlers = {
[capabilities.valve.ID] = {
[capabilities.valve.commands.open.NAME] = valve_open_handler,
[capabilities.valve.commands.close.NAME] = valve_close_handler,
}
},
Comment on lines +98 to +102

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did You check if Your device works with the zigbe-valve driver default handling ? (without this custom handling)

zigbee_handlers = {
attr = {
-- OnOff property reporting → valve event (to compensate for the defect of the parent driver's default mapping being skipped)
[OnOff.ID] = {
[OnOff.attributes.OnOff.ID] = onoff_attr_handler
},
Comment on lines +106 to +108

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did You check if Your device works with the zigbe-valve driver default handling ? (without this custom handling)

-- Battery percentage attribute reporting → battery event
[PowerConfiguration.ID] = {
[PowerConfiguration.attributes.BatteryPercentageRemaining.ID] = battery_percentage_handler
}
}
},
can_handle = is_sonoff_valve
}

return sonoff_valve_handler
Loading