diff --git a/drivers/SmartThings/zigbee-contact/src/multi-sensor/multi_utils.lua b/drivers/SmartThings/zigbee-contact/src/multi-sensor/multi_utils.lua index 863c544d6d..e24ec1097b 100644 --- a/drivers/SmartThings/zigbee-contact/src/multi-sensor/multi_utils.lua +++ b/drivers/SmartThings/zigbee-contact/src/multi-sensor/multi_utils.lua @@ -138,7 +138,7 @@ multi_utils.convert_to_signedInt16 = function(byte1, byte2) local finalValue local swapped = (byte2 << 8) | byte1 local sign_mask = 0x8000 - local int16mask = 0xFF + local int16mask = 0xFFFF local isNegative = (swapped & sign_mask) >> 15 if(isNegative == 1) then diff --git a/drivers/SmartThings/zigbee-contact/src/smartsense-multi/init.lua b/drivers/SmartThings/zigbee-contact/src/smartsense-multi/init.lua index 45d9521496..92fa777b7c 100644 --- a/drivers/SmartThings/zigbee-contact/src/smartsense-multi/init.lua +++ b/drivers/SmartThings/zigbee-contact/src/smartsense-multi/init.lua @@ -146,7 +146,19 @@ local function xyz_handler(driver, device, zb_rx) local x = multi_utils.convert_to_signedInt16(zb_rx.body.zcl_body.body_bytes:byte(1), zb_rx.body.zcl_body.body_bytes:byte(2)) local y = multi_utils.convert_to_signedInt16(zb_rx.body.zcl_body.body_bytes:byte(3), zb_rx.body.zcl_body.body_bytes:byte(4)) local z = multi_utils.convert_to_signedInt16(zb_rx.body.zcl_body.body_bytes:byte(5), zb_rx.body.zcl_body.body_bytes:byte(6)) - multi_utils.handle_three_axis_report(device, x, y, z) + device:emit_event(capabilities.threeAxis.threeAxis({value = {x, y, z}})) + if device.preferences["certifiedpreferences.garageSensor"] then + -- The sensor is mounted on the garage door vertically. Unlike the newer sensors, the z-axis is parallel to the ground + -- when the door is closed and perpendicular to the ground when the door is open. This is why we are using custom handling + -- instead of multi_utils.handle_three_axis_report. The values here were the same used in the original Groovy DTH + -- and in the protocol handler. + local abs_z = math.abs(z) + if abs_z > 825 then + device:emit_event(capabilities.contactSensor.contact.open()) + elseif abs_z < 100 then + device:emit_event(capabilities.contactSensor.contact.closed()) + end + end end local smartsense_multi = { diff --git a/drivers/SmartThings/zigbee-contact/src/test/test_smartsense_multi.lua b/drivers/SmartThings/zigbee-contact/src/test/test_smartsense_multi.lua index ddb167a9dd..9db8033062 100644 --- a/drivers/SmartThings/zigbee-contact/src/test/test_smartsense_multi.lua +++ b/drivers/SmartThings/zigbee-contact/src/test/test_smartsense_multi.lua @@ -336,27 +336,105 @@ test.register_coroutine_test( ) test.register_coroutine_test( - "Report from cluster 0xFC03, command 0x05 should be handled as: threeAxis(1050, -3, 9)", + "Report from cluster 0xFC03, command 0x05 should be handled as: threeAxis(1050, 3, 9)", function() test.socket.zigbee:__queue_receive({ mock_device.id, - build_three_axis_report_message(mock_device, "\x1A\x04\xFD\xFF\x09\x00") + build_three_axis_report_message(mock_device, "\x1A\x04\x03\x00\x09\x00") }) test.socket.capability:__set_channel_ordering("relaxed") - test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({1050, -3, 9})) ) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({1050, 3, 9})) ) end ) test.register_coroutine_test( - "Report from cluster 0xFC03, command 0x05 should be handled as: threeAxis(1123,-130,-24)", + "Report from cluster 0xFC03, command 0x05 should be handled as: threeAxis(-1050, -3, -9)", function() test.socket.zigbee:__queue_receive({ mock_device.id, - build_three_axis_report_message(mock_device, "\x63\x04\x7E\xFF\xE8\xFF") + build_three_axis_report_message(mock_device, "\xE6\xFB\xFD\xFF\xF7\xFF") }) test.socket.capability:__set_channel_ordering("relaxed") - test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({1123, -130, -24})) ) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({-1050, -3, -9})) ) end ) +test.register_coroutine_test( + "Report from cluster 0xFC03, command 0x05 should be handled as: threeAxis(10, 1020, 7)", + function() + test.socket.zigbee:__queue_receive({ + mock_device.id, + build_three_axis_report_message(mock_device, "\x0A\x00\xFC\x03\x07\x00") + }) + test.socket.capability:__set_channel_ordering("relaxed") + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({10, 1020, 7})) ) + end +) + +test.register_coroutine_test( + "Report from cluster 0xFC03, command 0x05 should be handled as: threeAxis(-10, -1020, -7)", + function() + test.socket.zigbee:__queue_receive({ + mock_device.id, + build_three_axis_report_message(mock_device, "\xF6\xFF\x04\xFC\xF9\xFF") + }) + test.socket.capability:__set_channel_ordering("relaxed") + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({-10, -1020, -7})) ) + end +) + +test.register_coroutine_test( + "Report from cluster 0xFC03, command 0x05 should be handled as: threeAxis(116, 4, 1003)", + function() + test.socket.zigbee:__queue_receive({ + mock_device.id, + build_three_axis_report_message(mock_device, "\x74\x00\x04\x00\xEB\x03") + }) + test.socket.capability:__set_channel_ordering("relaxed") + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({116, 4, 1003})) ) + end +) + +test.register_coroutine_test( + "Report from cluster 0xFC03, command 0x05 should be handled as: threeAxis(-116, -4, -1003)", + function() + test.socket.zigbee:__queue_receive({ + mock_device.id, + build_three_axis_report_message(mock_device, "\x8C\xFF\xFC\xFF\x15\xFC") + }) + test.socket.capability:__set_channel_ordering("relaxed") + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({-116, -4, -1003})) ) + end +) + +test.register_coroutine_test( + "Correct contact events should be generated when device is mounted on garage door", + function() + test.socket.device_lifecycle():__queue_receive({mock_device.id, "init"}) + test.socket.device_lifecycle():__queue_receive(mock_device:generate_info_changed( + { + preferences = { + ["certifiedpreferences.garageSensor"] = true + } + } + )) + test.wait_for_events() + test.socket.capability:__set_channel_ordering("relaxed") + test.socket.zigbee:__queue_receive({ + mock_device.id, + build_three_axis_report_message(mock_device, "\xF6\xFF\x04\xFC\x9D\xFF") + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({-10, -1020, -99})) ) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.contactSensor.contact.closed())) + + test.wait_for_events() + test.socket.zigbee:__queue_receive({ + mock_device.id, + build_three_axis_report_message(mock_device, "\x8C\xFF\xFC\xFF\xC6\xFC") + }) + test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.threeAxis.threeAxis({-116, -4, -826})) ) + test.socket.capability:__expect_send( mock_device:generate_test_message("main", capabilities.contactSensor.contact.open())) + end +) + test.run_registered_tests() \ No newline at end of file