-
Notifications
You must be signed in to change notification settings - Fork 464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Aqara] Cube T1 Pro #930
Merged
lelandblue
merged 10 commits into
SmartThingsCommunity:main
from
seojune79:Aqara-Cube-T1-Pro
Dec 1, 2023
+388
−0
Merged
[Aqara] Cube T1 Pro #930
Changes from 6 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
ad8cf57
add Aqara Cube T1 Pro
seojune79 c4592f3
Rename the profile from "aqara-cube-t1-pro" to "cube-t1-pro"
seojune79 54addef
Merge branch 'main' of https://github.com/SmartThingsCommunity/SmartT…
seojune79 85e336e
fixed thread call and removed the unused local
seojune79 cd50c51
fixed the thread
seojune79 8a8e509
changing folders
seojune79 2e0cbb1
remove can_handle
seojune79 8d639b4
add (1) refresh capability (2) BatteryVoltage handler (3) Testcases
seojune79 760bd66
Merge branch 'main' of https://github.com/SmartThingsCommunity/SmartT…
seojune79 a5c0857
remove unused variable utils
seojune79 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
id: stse.cubeAction | ||
version: 1 | ||
status: proposed | ||
name: Cube Action | ||
ephemeral: false | ||
attributes: | ||
cubeAction: | ||
schema: | ||
type: object | ||
properties: | ||
value: | ||
title: ActionType | ||
type: string | ||
enum: | ||
- noAction | ||
- shake | ||
- rotate | ||
- pickUpAndHold | ||
- flipToSide1 | ||
- flipToSide2 | ||
- flipToSide3 | ||
- flipToSide4 | ||
- flipToSide5 | ||
- flipToSide6 | ||
additionalProperties: false | ||
required: | ||
- value | ||
enumCommands: [] | ||
commands: {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
id: stse.cubeFace | ||
version: 1 | ||
status: proposed | ||
name: Cube Face | ||
ephemeral: false | ||
attributes: | ||
cubeFace: | ||
schema: | ||
type: object | ||
properties: | ||
value: | ||
title: CubeFace | ||
type: string | ||
enum: | ||
- face1Up | ||
- face2Up | ||
- face3Up | ||
- face4Up | ||
- face5Up | ||
- face6Up | ||
additionalProperties: false | ||
required: | ||
- value | ||
enumCommands: [] | ||
commands: {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
name: 'Aqara Cube' | ||
packageKey: 'aqara-cube' | ||
permissions: | ||
zigbee: {} | ||
description: "SmartThings driver for Aqara Cube devices" | ||
vendorSupportInformation: "https://www.aqara.com/en/support/" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
zigbeeManufacturer: | ||
- id: "Lumi/lumi.remote.cagl02" | ||
deviceLabel: Aqara Cube T1 Pro | ||
manufacturer: LUMI | ||
model: lumi.remote.cagl02 | ||
deviceProfileName: cube-t1-pro |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
name: cube-t1-pro | ||
components: | ||
- id: main | ||
capabilities: | ||
- id: stse.cubeAction | ||
version: 1 | ||
- id: stse.cubeFace | ||
version: 1 | ||
- id: battery | ||
version: 1 | ||
- id: firmwareUpdate | ||
version: 1 | ||
categories: | ||
- name: RemoteController | ||
metadata: | ||
mnmn: SolutionsEngineering | ||
vid: SmartThings-smartthings-Aqara_CubeT1Pro |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
local ZigbeeDriver = require "st.zigbee" | ||
local capabilities = require "st.capabilities" | ||
local data_types = require "st.zigbee.data_types" | ||
local cluster_base = require "st.zigbee.cluster_base" | ||
local battery_defaults = require "st.zigbee.defaults.battery_defaults" | ||
local clusters = require "st.zigbee.zcl.clusters" | ||
local PowerConfiguration = clusters.PowerConfiguration | ||
|
||
local PRI_CLU = 0xFCC0 | ||
local PRI_ATTR = 0x0009 | ||
local MFG_CODE = 0x115F | ||
|
||
local ROTATE_CLU = 0x000C | ||
local EVENT_CLU = 0x0012 | ||
local FACE_ATTR = 0x0149 | ||
local ACTION_ATTR = 0x0055 | ||
local CUBE_MODE = 0x0148 | ||
|
||
local cubeAction = capabilities["stse.cubeAction"] | ||
local cubeFace = capabilities["stse.cubeFace"] | ||
local cubeFaceVal = { "face1Up", "face2Up", "face3Up", "face4Up", "face5Up", "face6Up" } | ||
local cubeFlipToSideVal = { "flipToSide1", "flipToSide2", "flipToSide3", "flipToSide4", "flipToSide5", "flipToSide6" } | ||
|
||
local CUBEACTION_TIMER = "cubeAction_timer" | ||
local CUBEACTION_TIME = 3 | ||
|
||
local FINGERPRINTS = { mfr = "LUMI", model = "lumi.remote.cagl02" } | ||
|
||
local is_aqara_products = function(opts, driver, device, ...) | ||
return device:get_manufacturer() == FINGERPRINTS.mfr and device:get_model() == FINGERPRINTS.model | ||
end | ||
|
||
local callback_timer = function(device) | ||
return function() | ||
device:emit_event(cubeAction.cubeAction("noAction")) | ||
end | ||
end | ||
|
||
local function reset_thread(device) | ||
local timer = device:get_field(CUBEACTION_TIMER) | ||
if timer then | ||
device.thread:cancel_timer(timer) | ||
device:set_field(CUBEACTION_TIMER, nil) | ||
end | ||
device:set_field(CUBEACTION_TIMER, device.thread:call_with_delay(CUBEACTION_TIME, callback_timer(device))) | ||
end | ||
|
||
local function data_handler(driver, device, value, zb_rx) | ||
local val = value.value | ||
if val == 0x0000 then -- Shake | ||
reset_thread(device) | ||
device:emit_event(cubeAction.cubeAction("shake")) | ||
elseif val == 0x0004 then -- hold | ||
reset_thread(device) | ||
device:emit_event(cubeAction.cubeAction("pickUpAndHold")) | ||
elseif val & 0x0400 == 0x0400 then -- Flip to side | ||
local faceNum = val & 0x0007 | ||
reset_thread(device) | ||
device:emit_event(cubeAction.cubeAction(cubeFlipToSideVal[faceNum + 0x1])) | ||
end | ||
end | ||
|
||
local function rotate_handler(driver, device, value, zb_rx) | ||
-- Rotation | ||
reset_thread(device) | ||
device:emit_event(cubeAction.cubeAction("rotate")) | ||
end | ||
|
||
local function face_handler(driver, device, value, zb_rx) | ||
local faceNum = value.value | ||
device:emit_event(cubeFace.cubeFace(cubeFaceVal[faceNum + 1])) | ||
end | ||
|
||
local function device_init(driver, device) | ||
local power_configuration = { | ||
cluster = PowerConfiguration.ID, | ||
attribute = PowerConfiguration.attributes.BatteryVoltage.ID, | ||
minimum_interval = 30, | ||
maximum_interval = 3600, | ||
data_type = PowerConfiguration.attributes.BatteryVoltage.base_type, | ||
reportable_change = 1 | ||
} | ||
|
||
battery_defaults.build_linear_voltage_init(2.6, 3.0)(driver, device) | ||
|
||
device:add_configured_attribute(power_configuration) | ||
device:add_monitored_attribute(power_configuration) | ||
end | ||
|
||
local function device_added(self, device) | ||
-- Set private attribute | ||
device:send(cluster_base.write_manufacturer_specific_attribute(device, | ||
PRI_CLU, PRI_ATTR, MFG_CODE, data_types.Uint8, 1)) | ||
|
||
device:send(cluster_base.write_manufacturer_specific_attribute(device, | ||
PRI_CLU, CUBE_MODE, MFG_CODE, data_types.Uint8, 1)) | ||
device:emit_event(cubeAction.cubeAction("noAction")) | ||
device:emit_event(cubeFace.cubeFace("face1Up")) | ||
device:emit_event(capabilities.battery.battery(100)) | ||
end | ||
|
||
-- [[ register ]] | ||
local aqara_cube_t1_pro_handler = { | ||
NAME = "Aqara Cube T1 Pro", | ||
zigbee_handlers = { | ||
attr = { | ||
[EVENT_CLU] = { | ||
[ACTION_ATTR] = data_handler | ||
}, | ||
[ROTATE_CLU] = { | ||
[ACTION_ATTR] = rotate_handler, | ||
}, | ||
[PRI_CLU] = { | ||
[FACE_ATTR] = face_handler | ||
} | ||
} | ||
}, | ||
lifecycle_handlers = { | ||
init = device_init, | ||
added = device_added | ||
}, | ||
can_handle = is_aqara_products | ||
} | ||
|
||
local aqara_cube_t1_pro_driver = ZigbeeDriver("aqara_cube_t1_pro", aqara_cube_t1_pro_handler) | ||
aqara_cube_t1_pro_driver:run() | ||
|
159 changes: 159 additions & 0 deletions
159
drivers/Aqara/aqara-cube/src/test/test_aqara_cube_t1_pro.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
local test = require "integration_test" | ||
local cluster_base = require "st.zigbee.cluster_base" | ||
local t_utils = require "integration_test.utils" | ||
local zigbee_test_utils = require "integration_test.zigbee_test_utils" | ||
local capabilities = require "st.capabilities" | ||
local data_types = require "st.zigbee.data_types" | ||
|
||
local PRI_CLU = 0xFCC0 | ||
local PRI_ATTR = 0x0009 | ||
local MFG_CODE = 0x115F | ||
|
||
local ROTATE_CLU = 0x000C | ||
local EVENT_CLU = 0x0012 | ||
local FACE_ATTR = 0x0149 | ||
local ACTION_ATTR = 0x0055 | ||
local CUBE_MODE = 0x0148 | ||
|
||
local cubeAction = capabilities["stse.cubeAction"] | ||
local cubeFace = capabilities["stse.cubeFace"] | ||
test.add_package_capability("cubeAction.yaml") | ||
test.add_package_capability("cubeFace.yaml") | ||
|
||
local CUBEACTION_TIME = 3 | ||
|
||
|
||
local mock_device = test.mock_device.build_test_zigbee_device( | ||
{ | ||
profile = t_utils.get_profile_definition("cube-t1-pro.yml"), | ||
zigbee_endpoints = { | ||
[1] = { | ||
id = 1, | ||
manufacturer = "LUMI", | ||
model = "lumi.remote.cagl02", | ||
server_clusters = { PRI_CLU } | ||
} | ||
} | ||
} | ||
) | ||
|
||
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_coroutine_test( | ||
"lifecycle - added test", | ||
function() | ||
test.socket.zigbee:__set_channel_ordering("relaxed") | ||
test.socket.capability:__set_channel_ordering("relaxed") | ||
test.socket.device_lifecycle:__queue_receive({ mock_device.id, "added" }) | ||
-- private protocol enable | ||
test.socket.zigbee:__expect_send({ mock_device.id, | ||
cluster_base.write_manufacturer_specific_attribute(mock_device, PRI_CLU, PRI_ATTR, MFG_CODE, | ||
data_types.Uint8, 1) }) | ||
-- init | ||
test.socket.zigbee:__expect_send({ mock_device.id, | ||
cluster_base.write_manufacturer_specific_attribute(mock_device, PRI_CLU, CUBE_MODE, MFG_CODE, | ||
data_types.Uint8, 1) }) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", cubeAction.cubeAction("noAction"))) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", cubeFace.cubeFace("face1Up"))) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", capabilities.battery.battery(100))) | ||
end | ||
) | ||
|
||
test.register_coroutine_test( | ||
"data_handler test - shake", | ||
function() | ||
local attr_report_data = { | ||
{ ACTION_ATTR, data_types.Uint16.ID, 0x0000 } | ||
} | ||
test.socket.zigbee:__queue_receive({ | ||
mock_device.id, | ||
zigbee_test_utils.build_attribute_report(mock_device, EVENT_CLU, attr_report_data, MFG_CODE) | ||
}) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", | ||
cubeAction.cubeAction("shake"))) | ||
test.timer.__create_and_queue_test_time_advance_timer(CUBEACTION_TIME, "oneshot") | ||
test.mock_time.advance_time(CUBEACTION_TIME) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", | ||
cubeAction.cubeAction("noAction"))) | ||
end | ||
) | ||
|
||
test.register_coroutine_test( | ||
"data_handler test - pick up and hold", | ||
function() | ||
local attr_report_data = { | ||
{ ACTION_ATTR, data_types.Uint16.ID, 0x0004 } | ||
} | ||
test.socket.zigbee:__queue_receive({ | ||
mock_device.id, | ||
zigbee_test_utils.build_attribute_report(mock_device, EVENT_CLU, attr_report_data, MFG_CODE) | ||
}) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", | ||
cubeAction.cubeAction("pickUpAndHold"))) | ||
test.timer.__create_and_queue_test_time_advance_timer(CUBEACTION_TIME, "oneshot") | ||
test.mock_time.advance_time(CUBEACTION_TIME) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", | ||
cubeAction.cubeAction("noAction"))) | ||
end | ||
) | ||
|
||
test.register_coroutine_test( | ||
"data_handler test - flip to side 6", | ||
function() | ||
local attr_report_data = { | ||
{ ACTION_ATTR, data_types.Uint16.ID, 0x0405 } | ||
} | ||
test.socket.zigbee:__queue_receive({ | ||
mock_device.id, | ||
zigbee_test_utils.build_attribute_report(mock_device, EVENT_CLU, attr_report_data, MFG_CODE) | ||
}) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", | ||
cubeAction.cubeAction("flipToSide6"))) | ||
test.timer.__create_and_queue_test_time_advance_timer(CUBEACTION_TIME, "oneshot") | ||
test.mock_time.advance_time(CUBEACTION_TIME) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", | ||
cubeAction.cubeAction("noAction"))) | ||
end | ||
) | ||
|
||
test.register_coroutine_test( | ||
"rotate_handler test - rotation", | ||
function() | ||
local attr_report_data = { | ||
{ ACTION_ATTR, data_types.Uint16.ID, 0x0000 } | ||
} | ||
test.socket.zigbee:__queue_receive({ | ||
mock_device.id, | ||
zigbee_test_utils.build_attribute_report(mock_device, ROTATE_CLU, attr_report_data, MFG_CODE) | ||
}) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", | ||
cubeAction.cubeAction("rotate"))) | ||
test.timer.__create_and_queue_test_time_advance_timer(CUBEACTION_TIME, "oneshot") | ||
test.mock_time.advance_time(CUBEACTION_TIME) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", | ||
cubeAction.cubeAction("noAction"))) | ||
end | ||
) | ||
|
||
test.register_coroutine_test( | ||
"face_handler test - face up 1", | ||
function() | ||
local attr_report_data = { | ||
{ FACE_ATTR, data_types.Uint8.ID, 0x00 } | ||
} | ||
test.socket.zigbee:__queue_receive({ | ||
mock_device.id, | ||
zigbee_test_utils.build_attribute_report(mock_device, PRI_CLU, attr_report_data, MFG_CODE) | ||
}) | ||
test.socket.capability:__expect_send(mock_device:generate_test_message("main", | ||
cubeFace.cubeFace("face1Up"))) | ||
end | ||
) | ||
|
||
test.run_registered_tests() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as a base driver, you do not need to supply a
can_handle
functionThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was removed can_handle.