Skip to content
5 changes: 5 additions & 0 deletions drivers/SmartThings/zigbee-humidity-sensor/fingerprints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ zigbeeManufacturer:
manufacturer: eWeLink
model: SNZB-02P
deviceProfileName: humidity-temp-battery
- id: "SONOFF/SNZB-02M"
deviceLabel: "SONOFF SNZB-02M"
manufacturer: SONOFF
model: SNZB-02M
deviceProfileName: sonoff-humidity-temp-press-battery
- id: "SONOFF/SNZB-02DR2"
deviceLabel: "SONOFF SNZB-02DR2"
manufacturer: SONOFF
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: sonoff-humidity-temp-press-battery
components:
- id: main
capabilities:
- id: temperatureMeasurement
version: 1
- id: relativeHumidityMeasurement
version: 1
- id: atmosphericPressureMeasurement
version: 1
- id: battery
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: HumiditySensor
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- Copyright 2026 SmartThings, Inc.
-- Licensed under the Apache License, Version 2.0

local function can_handle(opts, driver, device, ...)
if device:get_model() == "SNZB-02M" then
return true, require("sonoff.SNZB-02M")
end

return false
end

return can_handle
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
-- Copyright 2026 SmartThings, Inc.
-- Licensed under the Apache License, Version 2.0

local capabilities = require "st.capabilities"
local clusters = require "st.zigbee.zcl.clusters"
local log = require "log"

local function convert_pressure_value(raw_value)
if raw_value == nil then
return nil
end

return raw_value / 10.0
end

local function pressure_report_handler(driver, device, value, zb_rx)
local pressure_value = convert_pressure_value(value.value)
if pressure_value == nil then
log.warn(string.format("SNZB-02M pressure report has no value: %s", tostring(value)))
return
end

log.debug(string.format("SNZB-02M pressure raw: %s, converted: %s kPa", tostring(value.value), tostring(pressure_value)))
device:emit_event(capabilities.atmosphericPressureMeasurement.atmosphericPressure({value = pressure_value, unit = "kPa"}))
end

local function refresh_handler(driver, device, command)
device:send(clusters.TemperatureMeasurement.attributes.MeasuredValue:read(device))
device:send(clusters.RelativeHumidity.attributes.MeasuredValue:read(device))
device:send(clusters.PressureMeasurement.attributes.MeasuredValue:read(device))
device:send(clusters.PowerConfiguration.attributes.BatteryPercentageRemaining:read(device))
end

local can_handle = require "sonoff.SNZB-02M.can_handle"

return {
NAME = "Sonoff SNZB-02M Sensor",
zigbee_handlers = {
attr = {
[clusters.PressureMeasurement.ID] = {
[clusters.PressureMeasurement.attributes.MeasuredValue.ID] = pressure_report_handler
}
}
},
capability_handlers = {
[capabilities.refresh.ID] = {
[capabilities.refresh.commands.refresh.NAME] = refresh_handler
}
},
can_handle = can_handle
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ local sub_drivers = {
lazy_load_if_possible("centralite-sensor"),
lazy_load_if_possible("heiman-sensor"),
lazy_load_if_possible("frient-sensor"),
lazy_load_if_possible("sonoff.SNZB-02M")
}
return sub_drivers
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
-- Copyright 2025 SmartThings, Inc.

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.

Suggested change
-- Copyright 2025 SmartThings, Inc.
-- Copyright 2026 SmartThings, Inc.

-- Licensed under the Apache License, Version 2.0

local test = require "integration_test"
local t_utils = require "integration_test.utils"
local zigbee_test_utils = require "integration_test.zigbee_test_utils"
local clusters = require "st.zigbee.zcl.clusters"
local capabilities = require "st.capabilities"

local PowerConfiguration = clusters.PowerConfiguration
local TemperatureMeasurement = clusters.TemperatureMeasurement
local RelativeHumidity = clusters.RelativeHumidity
local PressureMeasurement = clusters.PressureMeasurement

local mock_device = test.mock_device.build_test_zigbee_device(
{
profile = t_utils.get_profile_definition("sonoff-humidity-temp-press-battery.yml"),
zigbee_endpoints = {
[1] = {
id = 1,
manufacturer = "SONOFF",
model = "SNZB-02M",
server_clusters = { 0x0001, 0x0402, 0x0405, 0x0403 }
}
}
}
)

zigbee_test_utils.prepare_zigbee_env_info()
local function test_init()
test.mock_device.add_test_device(mock_device)
end

test.set_test_init_function(test_init)

test.register_message_test(
"Pressure report above 2000 should be divided by 1000",
{
{
channel = "zigbee",
direction = "receive",
message = {
mock_device.id,
PressureMeasurement.attributes.MeasuredValue:build_test_attr_report(mock_device, 10000)
}
},
{
channel = "capability",
direction = "send",
message = mock_device:generate_test_message("main",
capabilities.atmosphericPressureMeasurement.atmosphericPressure({ value = 10.0, unit = "kPa" }))
}
},
{
min_api_version = 14
}
)

test.register_message_test(
"Pressure report at or below 2000 should be divided by 10",
{
{
channel = "zigbee",
direction = "receive",
message = {
mock_device.id,
PressureMeasurement.attributes.MeasuredValue:build_test_attr_report(mock_device, 960)
}
},
{
channel = "capability",
direction = "send",
message = mock_device:generate_test_message("main",
capabilities.atmosphericPressureMeasurement.atmosphericPressure({ value = 96.0, unit = "kPa" }))
}
},
{
min_api_version = 14
}
)

test.register_message_test(
"Refresh should read temperature, humidity, pressure and battery",
{
{
channel = "capability",
direction = "receive",
message = { mock_device.id, { capability = "refresh", component = "main", command = "refresh", args = {} } }
},
{
channel = "zigbee",
direction = "send",
message = { mock_device.id, TemperatureMeasurement.attributes.MeasuredValue:read(mock_device) }
},
{
channel = "zigbee",
direction = "send",
message = { mock_device.id, RelativeHumidity.attributes.MeasuredValue:read(mock_device) }
},
{
channel = "zigbee",
direction = "send",
message = { mock_device.id, PressureMeasurement.attributes.MeasuredValue:read(mock_device) }
},
{
channel = "zigbee",
direction = "send",
message = { mock_device.id, PowerConfiguration.attributes.BatteryPercentageRemaining:read(mock_device) }
}
},
{
inner_block_ordering = "relaxed",
min_api_version = 14
}
)

test.run_registered_tests()
Loading