// Copyright 2022 Espressif Systems (Shanghai) PTE LTD // // 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. #include #include #include using namespace chip::app::Clusters; static const char *TAG = "cluster_command"; namespace esp_matter { namespace controller { namespace clusters { namespace on_off { static esp_err_t send_command(command_data_t *command_data, peer_device_t *remote_device, uint16_t remote_endpoint_id) { if (command_data->command_data_count != 0) { return ESP_ERR_INVALID_ARG; } switch (command_data->command_id) { case OnOff::Commands::On::Id: return esp_matter::cluster::on_off::command::send_on(remote_device, remote_endpoint_id); case OnOff::Commands::Off::Id: return esp_matter::cluster::on_off::command::send_off(remote_device, remote_endpoint_id); case OnOff::Commands::Toggle::Id: return esp_matter::cluster::on_off::command::send_toggle(remote_device, remote_endpoint_id); default: return ESP_ERR_NOT_SUPPORTED; } return ESP_ERR_NOT_SUPPORTED; } } // namespace on_off namespace level_control { static esp_err_t send_command(command_data_t *command_data, peer_device_t *remote_device, uint16_t remote_endpoint_id) { switch (command_data->command_id) { case LevelControl::Commands::Move::Id: if (command_data->command_data_count != 4) { ESP_LOGE(TAG, "The command date should in following order: move_mode, rate, option_mask, option_override"); return ESP_ERR_INVALID_ARG; } return esp_matter::cluster::level_control::command::send_move( remote_device, remote_endpoint_id, /* move_mode */ (uint8_t)strtol(command_data->command_data_str[0], NULL, 10), /* rate*/ (uint8_t)strtol(command_data->command_data_str[1], NULL, 10), /* option_mask */ (uint8_t)strtol(command_data->command_data_str[2], NULL, 10), /* option_override*/ (uint8_t)strtol(command_data->command_data_str[3], NULL, 10)); break; case LevelControl::Commands::MoveToLevel::Id: if (command_data->command_data_count != 4) { ESP_LOGE( TAG, "The command date should in following order: level, transition_time, option_mask, option_override"); return ESP_ERR_INVALID_ARG; } return esp_matter::cluster::level_control::command::send_move_to_level( remote_device, remote_endpoint_id, /* level */ (uint8_t)strtol(command_data->command_data_str[0], NULL, 10), /* transition_time */ (uint16_t)strtol(command_data->command_data_str[1], NULL, 10), /* option_mask */ (uint8_t)strtol(command_data->command_data_str[2], NULL, 10), /* option_override */ (uint8_t)strtol(command_data->command_data_str[3], NULL, 10)); break; case LevelControl::Commands::Step::Id: if (command_data->command_data_count != 5) { ESP_LOGE(TAG, "The command date should in following order: step_mode, step_size, transition_time, option_mask, " "option_override"); return ESP_ERR_INVALID_ARG; } return esp_matter::cluster::level_control::command::send_step( remote_device, remote_endpoint_id, /* step_mode */ (uint8_t)strtol(command_data->command_data_str[0], NULL, 10), /* step_size */ (uint8_t)strtol(command_data->command_data_str[1], NULL, 10), /* transition_time */ (uint16_t)strtol(command_data->command_data_str[2], NULL, 10), /* option_mask */ (uint8_t)strtol(command_data->command_data_str[3], NULL, 10), /* option_override */ (uint8_t)strtol(command_data->command_data_str[4], NULL, 10)); break; case LevelControl::Commands::Stop::Id: if (command_data->command_data_count != 2) { ESP_LOGE(TAG, "The command date should in following order: option_mask, option_override"); return ESP_ERR_INVALID_ARG; } return esp_matter::cluster::level_control::command::send_stop( remote_device, remote_endpoint_id, /* option_mask */ (uint8_t)strtol(command_data->command_data_str[0], NULL, 10), /* option_override */ (uint8_t)strtol(command_data->command_data_str[1], NULL, 10)); break; default: return ESP_ERR_NOT_SUPPORTED; break; } return ESP_ERR_NOT_SUPPORTED; } } // namespace level_control namespace color_control { static esp_err_t send_command(command_data_t *command_data, peer_device_t *remote_device, uint16_t remote_endpoint_id) { switch (command_data->command_id) { case ColorControl::Commands::MoveToHue::Id: if (command_data->command_data_count != 5) { ESP_LOGE(TAG, "The command date should in following order: hue, direction, transition_time, option_mask, " "option_override"); return ESP_ERR_INVALID_ARG; } return esp_matter::cluster::color_control::command::send_move_to_hue( remote_device, remote_endpoint_id, /* hue */ (uint8_t)strtol(command_data->command_data_str[0], NULL, 10), /* direction */ (uint8_t)strtol(command_data->command_data_str[1], NULL, 10), /* transition_time */ (uint16_t)strtol(command_data->command_data_str[2], NULL, 10), /* option_mask */ (uint8_t)strtol(command_data->command_data_str[3], NULL, 10), /* option_override */ (uint8_t)strtol(command_data->command_data_str[4], NULL, 10)); break; case ColorControl::Commands::MoveToSaturation::Id: if (command_data->command_data_count != 4) { ESP_LOGE(TAG, "The command date should in following order: saturation, transition_time, option_mask, " "option_override"); return ESP_ERR_INVALID_ARG; } return esp_matter::cluster::color_control::command::send_move_to_saturation( remote_device, remote_endpoint_id, /* saturation */ (uint8_t)strtol(command_data->command_data_str[0], NULL, 10), /* transition_time */ (uint16_t)strtol(command_data->command_data_str[1], NULL, 10), /* option_mask */ (uint8_t)strtol(command_data->command_data_str[2], NULL, 10), /* option_override */ (uint8_t)strtol(command_data->command_data_str[3], NULL, 10)); break; case ColorControl::Commands::MoveToHueAndSaturation::Id: if (command_data->command_data_count != 5) { ESP_LOGE(TAG, "The command date should in following order: hue, saturation, transition_time, option_mask, " "option_override"); return ESP_ERR_INVALID_ARG; } return esp_matter::cluster::color_control::command::send_move_to_hue_and_saturation( remote_device, remote_endpoint_id, /* hue */ (uint8_t)strtol(command_data->command_data_str[0], NULL, 10), /* saturation */ (uint8_t)strtol(command_data->command_data_str[1], NULL, 10), /* transition_time */ (uint16_t)strtol(command_data->command_data_str[2], NULL, 10), /* option_mask */ (uint8_t)strtol(command_data->command_data_str[3], NULL, 10), /* option_override */ (uint8_t)strtol(command_data->command_data_str[4], NULL, 10)); break; default: return ESP_ERR_NOT_SUPPORTED; break; } return ESP_ERR_NOT_SUPPORTED; } } // namespace color_control } // namespace clusters void cluster_command::on_device_connected_fcn(void *context, ExchangeManager &exchangeMgr, SessionHandle &sessionHandle) { cluster_command *cmd = reinterpret_cast(context); chip::OperationalDeviceProxy device_proxy(&exchangeMgr, sessionHandle); switch (cmd->m_command_data->cluster_id) { case OnOff::Id: clusters::on_off::send_command(cmd->m_command_data, &device_proxy, cmd->m_endpoint_id); break; case LevelControl::Id: clusters::level_control::send_command(cmd->m_command_data, &device_proxy, cmd->m_endpoint_id); break; case ColorControl::Id: clusters::color_control::send_command(cmd->m_command_data, &device_proxy, cmd->m_endpoint_id); break; default: break; } chip::Platform::Delete(cmd); return; } void cluster_command::on_device_connection_failure_fcn(void *context, const ScopedNodeId &peerId, CHIP_ERROR error) { cluster_command *cmd = reinterpret_cast(context); chip::Platform::Delete(cmd); return; } esp_err_t cluster_command::send_command() { if (CHIP_NO_ERROR == commissioner::get_device_commissioner()->GetConnectedDevice(m_node_id, &on_device_connected_cb, &on_device_connection_failure_cb)) { return ESP_OK; } chip::Platform::Delete(this); return ESP_FAIL; } esp_err_t send_invoke_cluster_command(uint64_t node_id, uint16_t endpoint_id, int cmd_data_argc, char **cmd_data_argv) { command_data_t *command_data = (command_data_t *)calloc(1, sizeof(command_data_t)); if (!command_data) { ESP_LOGE(TAG, "Failed to alloc memory for command data"); return ESP_ERR_NO_MEM; } command_data->cluster_id = (uint32_t)strtol(cmd_data_argv[0], NULL, 10); command_data->command_id = (uint32_t)strtol(cmd_data_argv[1], NULL, 10); command_data->command_data_count = cmd_data_argc - 2; for (size_t idx = 0; idx < command_data->command_data_count; idx++) { strncpy(command_data->command_data_str[idx], cmd_data_argv[2 + idx], strnlen(cmd_data_argv[2 + idx], k_max_command_data_str_len)); command_data->command_data_str[idx][controller::k_max_command_data_str_len - 1] = 0; } cluster_command *cmd = chip::Platform::New(node_id, endpoint_id, command_data); if (!cmd) { ESP_LOGE(TAG, "Failed to alloc memory for cluster_command"); return ESP_ERR_NO_MEM; } return cmd->send_command(); } } // namespace controller } // namespace esp_matter