| /* |
| * |
| * Copyright (c) 2023 Project CHIP Authors |
| * All rights reserved. |
| * |
| * 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 "AppTask.h" |
| #include "Device.h" |
| |
| #include <app-common/zap-generated/attributes/Accessors.h> |
| #include <app/reporting/reporting.h> |
| #include <app/util/endpoint-config-api.h> |
| #include <lib/support/ZclString.h> |
| |
| LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); |
| |
| namespace { |
| const struct pwm_dt_spec sPwmRgbSpecBlueLed = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0)); |
| } // namespace |
| |
| AppTask AppTask::sAppTask; |
| #include <app/InteractionModelEngine.h> |
| |
| int AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, const Span<const EmberAfDeviceType> & deviceTypeList, |
| const Span<DataVersion> & dataVersionStorage, chip::EndpointId parentEndpointId); |
| CHIP_ERROR RemoveDeviceEndpoint(Device * dev); |
| void HandleDeviceTempSensorStatusChanged(DeviceTempSensor * dev, DeviceTempSensor::Changed_t itemChangedMask); |
| Protocols::InteractionModel::Status HandleReadTempMeasurementAttribute(DeviceTempSensor * dev, chip::AttributeId attributeId, |
| uint8_t * buffer, uint16_t maxReadLength); |
| |
| static const int kNodeLabelSize = 32; |
| // Current ZCL implementation of Struct uses a max-size array of 254 bytes |
| static const int kDescriptorAttributeArraySize = 254; |
| |
| static EndpointId gCurrentEndpointId; |
| static EndpointId gFirstDynamicEndpointId; |
| |
| static Device * gDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT]; // number of dynamic endpoints count |
| |
| const int16_t minMeasuredValue = -27315; |
| const int16_t maxMeasuredValue = 32766; |
| const int16_t initialMeasuredValue = 100; |
| |
| // 5 Bridged devices |
| static Device gLight1("Light 1", "Office"); |
| static Device gLight2("Light 2", "Office"); |
| static Device gLight3("Light 3", "Kitchen"); |
| static Device gLight4("Light 4", "Kitchen"); |
| static DeviceTempSensor TempSensor1("TempSensor 1", "Office", minMeasuredValue, maxMeasuredValue, initialMeasuredValue); |
| |
| // (taken from src/app/zap-templates/zcl/data-model/chip/matter-devices.xml) |
| #define DEVICE_TYPE_BRIDGED_NODE 0x0013 |
| // (taken from lo-devices.xml) |
| #define DEVICE_TYPE_LO_ON_OFF_LIGHT 0x0100 |
| #define DEVICE_TYPE_ROOT_NODE 0x0016 |
| #define DEVICE_TYPE_BRIDGE 0x000e |
| #define DEVICE_TYPE_TEMP_SENSOR 0x0302 |
| // Device Version for dynamic endpoints: |
| #define DEVICE_VERSION_DEFAULT 1 |
| |
| /* REVISION definitions: |
| */ |
| |
| #define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u) |
| #define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u) |
| #define ZCL_FIXED_LABEL_CLUSTER_REVISION (1u) |
| #define ZCL_ON_OFF_CLUSTER_REVISION (4u) |
| #define ZCL_TEMPERATURE_SENSOR_CLUSTER_REVISION (4u) |
| #define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u) |
| #define ZCL_TEMPERATURE_SENSOR_FEATURE_MAP (0u) |
| |
| /* BRIDGED DEVICE ENDPOINT: contains the following clusters: |
| - On/Off |
| - Descriptor |
| - Bridged Device Basic Information |
| */ |
| |
| // Declare On/Off cluster attributes |
| DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(onOffAttrs) |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::OnOff::Attributes::OnOff::Id, BOOLEAN, 1, 0), /* on/off */ |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::OnOff::Attributes::ClusterRevision::Id, INT16U, ZCL_ON_OFF_CLUSTER_REVISION, 0), |
| DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); |
| |
| // Declare Descriptor cluster attributes |
| DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs) |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, |
| 0), /* device list */ |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, |
| 0), /* server list */ |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, |
| 0), /* client list */ |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, |
| 0), /* parts list */ |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::Descriptor::Attributes::ClusterRevision::Id, INT16U, ZCL_DESCRIPTOR_CLUSTER_REVISION, |
| 0), /* cluster revision */ |
| DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); |
| |
| // Declare Bridged Device Basic Information cluster attributes |
| DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(bridgedDeviceBasicAttrs) |
| DECLARE_DYNAMIC_ATTRIBUTE(chip::app::Clusters::BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, |
| kNodeLabelSize, 0), /* NodeLabel */ |
| DECLARE_DYNAMIC_ATTRIBUTE(chip::app::Clusters::BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, |
| 0), /* Reachable */ |
| DECLARE_DYNAMIC_ATTRIBUTE(chip::app::Clusters::BridgedDeviceBasicInformation::Attributes::ClusterRevision::Id, INT16U, |
| ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION, 0), /* cluster revision */ |
| DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); |
| |
| // Declare Cluster List for Bridged Light endpoint |
| // TODO: It's not clear whether it would be better to get the command lists from |
| // the ZAP config on our last fixed endpoint instead. |
| constexpr CommandId onOffIncomingCommands[] = { |
| app::Clusters::OnOff::Commands::Off::Id, |
| app::Clusters::OnOff::Commands::On::Id, |
| app::Clusters::OnOff::Commands::Toggle::Id, |
| app::Clusters::OnOff::Commands::OffWithEffect::Id, |
| app::Clusters::OnOff::Commands::OnWithRecallGlobalScene::Id, |
| app::Clusters::OnOff::Commands::OnWithTimedOff::Id, |
| kInvalidCommandId, |
| }; |
| |
| DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedLightClusters) |
| DECLARE_DYNAMIC_CLUSTER(Clusters::OnOff::Id, onOffAttrs, ZAP_CLUSTER_MASK(SERVER), onOffIncomingCommands, nullptr), |
| DECLARE_DYNAMIC_CLUSTER(Clusters::Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), |
| DECLARE_DYNAMIC_CLUSTER(chip::app::Clusters::BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, |
| ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END; |
| |
| // ----------------------------Temperature sensor----------------------------------------------- |
| DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(tempSensorAttrs) |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::TemperatureMeasurement::Attributes::MeasuredValue::Id, INT16S, 2, 0), /* Measured Value */ |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::TemperatureMeasurement::Attributes::MinMeasuredValue::Id, INT16S, 2, |
| 0), /* Min Measured Value */ |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::TemperatureMeasurement::Attributes::MaxMeasuredValue::Id, INT16S, 2, |
| 0), /* Max Measured Value */ |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::TemperatureMeasurement::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* FeatureMap */ |
| DECLARE_DYNAMIC_ATTRIBUTE(Clusters::TemperatureMeasurement::Attributes::ClusterRevision::Id, INT16U, |
| ZCL_TEMPERATURE_SENSOR_CLUSTER_REVISION, 0), /* cluster revision */ |
| DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); |
| |
| // TEMPERATURE SENSOR ENDPOINT: contains the following clusters: |
| // - Temperature measurement |
| // - Descriptor |
| // - Bridged Device Basic Information |
| DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedTempSensorClusters) |
| DECLARE_DYNAMIC_CLUSTER(Clusters::TemperatureMeasurement::Id, tempSensorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), |
| DECLARE_DYNAMIC_CLUSTER(Clusters::Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), |
| DECLARE_DYNAMIC_CLUSTER(Clusters::BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, |
| nullptr), |
| DECLARE_DYNAMIC_CLUSTER_LIST_END; |
| |
| // Declare Bridged Light endpoint |
| DECLARE_DYNAMIC_ENDPOINT(bridgedTempSensorEndpoint, bridgedTempSensorClusters); |
| DataVersion gTempSensor1DataVersions[ArraySize(bridgedTempSensorClusters)]; |
| |
| // Declare Bridged Light endpoint |
| DECLARE_DYNAMIC_ENDPOINT(bridgedLightEndpoint, bridgedLightClusters); |
| |
| DataVersion gLight1DataVersions[ArraySize(bridgedLightClusters)]; |
| DataVersion gLight2DataVersions[ArraySize(bridgedLightClusters)]; |
| DataVersion gLight3DataVersions[ArraySize(bridgedLightClusters)]; |
| DataVersion gLight4DataVersions[ArraySize(bridgedLightClusters)]; |
| // DataVersion gThermostatDataVersions[ArraySize(thermostatAttrs)]; |
| |
| const EmberAfDeviceType gRootDeviceTypes[] = { { DEVICE_TYPE_ROOT_NODE, DEVICE_VERSION_DEFAULT } }; |
| const EmberAfDeviceType gAggregateNodeDeviceTypes[] = { { DEVICE_TYPE_BRIDGE, DEVICE_VERSION_DEFAULT } }; |
| |
| const EmberAfDeviceType gBridgedOnOffDeviceTypes[] = { { DEVICE_TYPE_LO_ON_OFF_LIGHT, DEVICE_VERSION_DEFAULT }, |
| { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT } }; |
| |
| const EmberAfDeviceType gBridgedTempSensorDeviceTypes[] = { { DEVICE_TYPE_TEMP_SENSOR, DEVICE_VERSION_DEFAULT }, |
| { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT } }; |
| |
| int AddDeviceEndpoint(Device * dev, EmberAfEndpointType * ep, const Span<const EmberAfDeviceType> & deviceTypeList, |
| const Span<DataVersion> & dataVersionStorage, chip::EndpointId parentEndpointId) |
| { |
| uint8_t index = 0; |
| while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) |
| { |
| if (NULL == gDevices[index]) |
| { |
| gDevices[index] = dev; |
| CHIP_ERROR err; |
| while (true) |
| { |
| dev->SetEndpointId(gCurrentEndpointId); |
| err = |
| emberAfSetDynamicEndpoint(index, gCurrentEndpointId, ep, dataVersionStorage, deviceTypeList, parentEndpointId); |
| if (err == CHIP_NO_ERROR) |
| { |
| ChipLogProgress(DeviceLayer, "Added device %s to dynamic endpoint %d (index=%d)", dev->GetName(), |
| gCurrentEndpointId, index); |
| return index; |
| } |
| else if (err != CHIP_ERROR_ENDPOINT_EXISTS) |
| { |
| return -1; |
| } |
| // Handle wrap condition |
| if (++gCurrentEndpointId < gFirstDynamicEndpointId) |
| { |
| gCurrentEndpointId = gFirstDynamicEndpointId; |
| } |
| } |
| } |
| index++; |
| } |
| ChipLogProgress(DeviceLayer, "Failed to add dynamic endpoint: No endpoints available!"); |
| return -1; |
| } |
| |
| CHIP_ERROR RemoveDeviceEndpoint(Device * dev) |
| { |
| for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; index++) |
| { |
| if (gDevices[index] == dev) |
| { |
| // Silence complaints about unused ep when progress logging |
| // disabled. |
| [[maybe_unused]] EndpointId ep = emberAfClearDynamicEndpoint(index); |
| gDevices[index] = NULL; |
| ChipLogProgress(DeviceLayer, "Removed device %s from dynamic endpoint %d (index=%d)", dev->GetName(), ep, index); |
| return CHIP_NO_ERROR; |
| } |
| } |
| return CHIP_ERROR_INTERNAL; |
| } |
| |
| Protocols::InteractionModel::Status HandleReadBridgedDeviceBasicAttribute(Device * dev, chip::AttributeId attributeId, |
| uint8_t * buffer, uint16_t maxReadLength) |
| { |
| using namespace chip::app::Clusters::BridgedDeviceBasicInformation::Attributes; |
| ChipLogProgress(DeviceLayer, "HandleReadBridgedDeviceBasicAttribute: attrId=%" PRIu32 ", maxReadLength=%u", attributeId, |
| maxReadLength); |
| |
| if ((attributeId == Reachable::Id) && (maxReadLength == 1)) |
| { |
| *buffer = dev->IsReachable() ? 1 : 0; |
| } |
| else if ((attributeId == NodeLabel::Id) && (maxReadLength == 32)) |
| { |
| MutableByteSpan zclNameSpan(buffer, maxReadLength); |
| MakeZclCharString(zclNameSpan, dev->GetName()); |
| } |
| else if ((attributeId == FeatureMap::Id) && (maxReadLength == 4)) |
| { |
| uint32_t featureMap = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP; |
| memcpy(buffer, &featureMap, sizeof(featureMap)); |
| } |
| else if ((attributeId == ClusterRevision::Id) && (maxReadLength == 4)) |
| { |
| uint16_t clusterRevision = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION; |
| memcpy(buffer, &clusterRevision, sizeof(clusterRevision)); |
| } |
| else |
| { |
| return Protocols::InteractionModel::Status::Failure; |
| } |
| |
| return Protocols::InteractionModel::Status::Success; |
| } |
| |
| Protocols::InteractionModel::Status HandleReadOnOffAttribute(Device * dev, chip::AttributeId attributeId, uint8_t * buffer, |
| uint16_t maxReadLength) |
| { |
| ChipLogProgress(DeviceLayer, "HandleReadOnOffAttribute: attrId=%" PRIu32 ", maxReadLength=%u", attributeId, maxReadLength); |
| |
| if ((attributeId == Clusters::OnOff::Attributes::OnOff::Id) && (maxReadLength == 1)) |
| { |
| *buffer = dev->IsOn() ? 1 : 0; |
| } |
| else if ((attributeId == Clusters::OnOff::Attributes::ClusterRevision::Id) && (maxReadLength == 4)) |
| { |
| uint16_t clusterRevision = ZCL_ON_OFF_CLUSTER_REVISION; |
| memcpy(buffer, &clusterRevision, sizeof(clusterRevision)); |
| } |
| else |
| { |
| return Protocols::InteractionModel::Status::Failure; |
| } |
| |
| return Protocols::InteractionModel::Status::Success; |
| } |
| |
| Protocols::InteractionModel::Status HandleWriteOnOffAttribute(Device * dev, chip::AttributeId attributeId, uint8_t * buffer) |
| { |
| ChipLogProgress(DeviceLayer, "HandleWriteOnOffAttribute: attrId=%" PRIu32, attributeId); |
| |
| ReturnErrorCodeIf((attributeId != Clusters::OnOff::Attributes::OnOff::Id) || (!dev->IsReachable()), |
| Protocols::InteractionModel::Status::Failure); |
| dev->SetOnOff(*buffer == 1); |
| return Protocols::InteractionModel::Status::Success; |
| } |
| |
| Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, |
| const EmberAfAttributeMetadata * attributeMetadata, |
| uint8_t * buffer, uint16_t maxReadLength) |
| { |
| using namespace Clusters; |
| |
| uint16_t endpointIndex = emberAfGetDynamicIndexFromEndpoint(endpoint); |
| |
| if ((endpointIndex < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) && (gDevices[endpointIndex] != NULL)) |
| { |
| Device * dev = gDevices[endpointIndex]; |
| |
| if (clusterId == BridgedDeviceBasicInformation::Id) |
| { |
| return HandleReadBridgedDeviceBasicAttribute(dev, attributeMetadata->attributeId, buffer, maxReadLength); |
| } |
| else if (clusterId == OnOff::Id) |
| { |
| return HandleReadOnOffAttribute(dev, attributeMetadata->attributeId, buffer, maxReadLength); |
| } |
| else if (clusterId == TemperatureMeasurement::Id) |
| { |
| return HandleReadTempMeasurementAttribute(static_cast<DeviceTempSensor *>(dev), attributeMetadata->attributeId, buffer, |
| maxReadLength); |
| } |
| } |
| |
| return Protocols::InteractionModel::Status::Failure; |
| } |
| |
| Protocols::InteractionModel::Status emberAfExternalAttributeWriteCallback(EndpointId endpoint, ClusterId clusterId, |
| const EmberAfAttributeMetadata * attributeMetadata, |
| uint8_t * buffer) |
| { |
| uint16_t endpointIndex = emberAfGetDynamicIndexFromEndpoint(endpoint); |
| |
| if (endpointIndex < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) |
| { |
| Device * dev = gDevices[endpointIndex]; |
| |
| if ((dev->IsReachable()) && (clusterId == Clusters::OnOff::Id)) |
| { |
| return HandleWriteOnOffAttribute(dev, attributeMetadata->attributeId, buffer); |
| } |
| } |
| |
| return Protocols::InteractionModel::Status::Failure; |
| } |
| |
| namespace { |
| void CallReportingCallback(intptr_t closure) |
| { |
| auto path = reinterpret_cast<app::ConcreteAttributePath *>(closure); |
| MatterReportingAttributeChangeCallback(*path); |
| Platform::Delete(path); |
| } |
| |
| void ScheduleReportingCallback(Device * dev, ClusterId cluster, AttributeId attribute) |
| { |
| auto * path = Platform::New<app::ConcreteAttributePath>(dev->GetEndpointId(), cluster, attribute); |
| DeviceLayer::PlatformMgr().ScheduleWork(CallReportingCallback, reinterpret_cast<intptr_t>(path)); |
| } |
| } // anonymous namespace |
| |
| void HandleDeviceStatusChanged(Device * dev, Device::Changed_t itemChangedMask) |
| { |
| using namespace chip::app::Clusters; |
| if (itemChangedMask & Device::kChanged_Reachable) |
| { |
| ScheduleReportingCallback(dev, BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::Reachable::Id); |
| } |
| |
| if (itemChangedMask & Device::kChanged_State) |
| { |
| ScheduleReportingCallback(dev, OnOff::Id, OnOff::Attributes::OnOff::Id); |
| } |
| |
| if (itemChangedMask & Device::kChanged_Name) |
| { |
| ScheduleReportingCallback(dev, BridgedDeviceBasicInformation::Id, BridgedDeviceBasicInformation::Attributes::NodeLabel::Id); |
| } |
| } |
| |
| bool emberAfActionsClusterInstantActionCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, |
| const Clusters::Actions::Commands::InstantAction::DecodableType & commandData) |
| { |
| // No actions are implemented, just return status NotFound. |
| commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); |
| return true; |
| } |
| |
| CHIP_ERROR AppTask::Init(void) |
| { |
| // Init lighting manager |
| uint8_t minLightLevel = kDefaultMinLevel; |
| Clusters::LevelControl::Attributes::MinLevel::Get(kExampleEndpointId, &minLightLevel); |
| |
| uint8_t maxLightLevel = kDefaultMaxLevel; |
| Clusters::LevelControl::Attributes::MaxLevel::Get(kExampleEndpointId, &maxLightLevel); |
| |
| // Initialize PWM LED |
| CHIP_ERROR err = sAppTask.mPwmRgbBlueLed.Init(&sPwmRgbSpecBlueLed, minLightLevel, maxLightLevel, maxLightLevel); |
| if (err != CHIP_NO_ERROR) |
| { |
| LOG_ERR("Blue RGB PWM Device Init fail"); |
| return err; |
| } |
| |
| sAppTask.mPwmRgbBlueLed.SetCallbacks(ActionInitiated, ActionCompleted, nullptr); |
| |
| #if APP_USE_EXAMPLE_START_BUTTON |
| SetExampleButtonCallbacks(LightingActionEventHandler); |
| #endif |
| InitCommonParts(); |
| |
| memset(gDevices, 0, sizeof(gDevices)); |
| |
| gLight1.SetReachable(true); |
| gLight2.SetReachable(true); |
| gLight3.SetReachable(true); |
| gLight4.SetReachable(true); |
| TempSensor1.SetReachable(true); |
| |
| // Whenever bridged device changes its state |
| gLight1.SetChangeCallback(&HandleDeviceStatusChanged); |
| gLight2.SetChangeCallback(&HandleDeviceStatusChanged); |
| gLight3.SetChangeCallback(&HandleDeviceStatusChanged); |
| gLight4.SetChangeCallback(&HandleDeviceStatusChanged); |
| TempSensor1.SetChangeCallback(&HandleDeviceTempSensorStatusChanged); |
| |
| PlatformMgr().ScheduleWork(InitServer, reinterpret_cast<intptr_t>(nullptr)); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| void AppTask::InitServer(intptr_t context) |
| { |
| // Set starting endpoint id where dynamic endpoints will be assigned, which |
| // will be the next consecutive endpoint id after the last fixed endpoint. |
| gFirstDynamicEndpointId = static_cast<chip::EndpointId>( |
| static_cast<int>(emberAfEndpointFromIndex(static_cast<uint16_t>(emberAfFixedEndpointCount() - 1))) + 1); |
| gCurrentEndpointId = gFirstDynamicEndpointId; |
| |
| // Disable last fixed endpoint, which is used as a placeholder for all of the |
| // supported clusters so that ZAP will generate the requisite code. |
| emberAfEndpointEnableDisable(emberAfEndpointFromIndex(static_cast<uint16_t>(emberAfFixedEndpointCount() - 1)), false); |
| |
| // A bridge has root node device type on EP0 and aggregate node device type (bridge) at EP1 |
| emberAfSetDeviceTypeList(0, Span<const EmberAfDeviceType>(gRootDeviceTypes)); |
| emberAfSetDeviceTypeList(1, Span<const EmberAfDeviceType>(gAggregateNodeDeviceTypes)); |
| |
| // Add lights 1..3 --> will be mapped to ZCL endpoints 3, 4, 5 |
| AddDeviceEndpoint(&gLight1, &bridgedLightEndpoint, Span<const EmberAfDeviceType>(gBridgedOnOffDeviceTypes), |
| Span<DataVersion>(gLight1DataVersions), 1); |
| AddDeviceEndpoint(&gLight2, &bridgedLightEndpoint, Span<const EmberAfDeviceType>(gBridgedOnOffDeviceTypes), |
| Span<DataVersion>(gLight2DataVersions), 1); |
| AddDeviceEndpoint(&gLight3, &bridgedLightEndpoint, Span<const EmberAfDeviceType>(gBridgedOnOffDeviceTypes), |
| Span<DataVersion>(gLight3DataVersions), 1); |
| |
| // Remove Light 2 -- Lights 1 & 3 will remain mapped to endpoints 3 & 5 |
| RemoveDeviceEndpoint(&gLight2); |
| |
| // Add Light 4 -- > will be mapped to ZCL endpoint 6 |
| AddDeviceEndpoint(&gLight4, &bridgedLightEndpoint, Span<const EmberAfDeviceType>(gBridgedOnOffDeviceTypes), |
| Span<DataVersion>(gLight4DataVersions), 1); |
| |
| // Re-add Light 2 -- > will be mapped to ZCL endpoint 7 |
| AddDeviceEndpoint(&gLight2, &bridgedLightEndpoint, Span<const EmberAfDeviceType>(gBridgedOnOffDeviceTypes), |
| Span<DataVersion>(gLight2DataVersions), 1); |
| |
| // Add Temperature Sensor devices --> will be mapped to endpoint 8 |
| AddDeviceEndpoint(&TempSensor1, &bridgedTempSensorEndpoint, Span<const EmberAfDeviceType>(gBridgedTempSensorDeviceTypes), |
| Span<DataVersion>(gTempSensor1DataVersions), 1); |
| } |
| |
| void HandleDeviceTempSensorStatusChanged(DeviceTempSensor * dev, DeviceTempSensor::Changed_t itemChangedMask) |
| { |
| using namespace Clusters; |
| if (itemChangedMask & |
| (DeviceTempSensor::kChanged_Reachable | DeviceTempSensor::kChanged_Name | DeviceTempSensor::kChanged_Location)) |
| { |
| HandleDeviceStatusChanged(static_cast<Device *>(dev), (Device::Changed_t) itemChangedMask); |
| } |
| if (itemChangedMask & DeviceTempSensor::kChanged_MeasurementValue) |
| { |
| ScheduleReportingCallback(dev, TemperatureMeasurement::Id, TemperatureMeasurement::Attributes::MeasuredValue::Id); |
| } |
| } |
| |
| Protocols::InteractionModel::Status HandleReadTempMeasurementAttribute(DeviceTempSensor * dev, chip::AttributeId attributeId, |
| uint8_t * buffer, uint16_t maxReadLength) |
| { |
| using namespace Clusters::TemperatureMeasurement::Attributes; |
| |
| if ((attributeId == MeasuredValue::Id) && (maxReadLength == 2)) |
| { |
| int16_t measuredValue = dev->GetMeasuredValue(); |
| memcpy(buffer, &measuredValue, sizeof(measuredValue)); |
| } |
| else if ((attributeId == MinMeasuredValue::Id) && (maxReadLength == 2)) |
| { |
| int16_t minValue = dev->mMin; |
| memcpy(buffer, &minValue, sizeof(minValue)); |
| } |
| else if ((attributeId == MaxMeasuredValue::Id) && (maxReadLength == 2)) |
| { |
| int16_t maxValue = dev->mMax; |
| memcpy(buffer, &maxValue, sizeof(maxValue)); |
| } |
| else if ((attributeId == FeatureMap::Id) && (maxReadLength == 4)) |
| { |
| uint32_t featureMap = ZCL_TEMPERATURE_SENSOR_FEATURE_MAP; |
| memcpy(buffer, &featureMap, sizeof(featureMap)); |
| } |
| else if ((attributeId == ClusterRevision::Id) && (maxReadLength == 4)) |
| { |
| uint16_t clusterRevision = ZCL_TEMPERATURE_SENSOR_CLUSTER_REVISION; |
| memcpy(buffer, &clusterRevision, sizeof(clusterRevision)); |
| } |
| else |
| { |
| return Protocols::InteractionModel::Status::Failure; |
| } |
| |
| return Protocols::InteractionModel::Status::Success; |
| } |
| |
| void AppTask::LightingActionEventHandler(AppEvent * aEvent) |
| { |
| PWMDevice::Action_t action = PWMDevice::INVALID_ACTION; |
| int32_t actor = 0; |
| |
| if (aEvent->Type == AppEvent::kEventType_Lighting) |
| { |
| action = static_cast<PWMDevice::Action_t>(aEvent->LightingEvent.Action); |
| actor = aEvent->LightingEvent.Actor; |
| } |
| else if (aEvent->Type == AppEvent::kEventType_Button) |
| { |
| action = sAppTask.mPwmRgbBlueLed.IsTurnedOn() ? PWMDevice::OFF_ACTION : PWMDevice::ON_ACTION; |
| actor = AppEvent::kEventType_Button; |
| } |
| |
| if (action != PWMDevice::INVALID_ACTION && (!sAppTask.mPwmRgbBlueLed.InitiateAction(action, actor, NULL))) |
| { |
| LOG_INF("Action is in progress or active"); |
| } |
| } |
| |
| void AppTask::ActionInitiated(PWMDevice::Action_t aAction, int32_t aActor) |
| { |
| if (aAction == PWMDevice::ON_ACTION) |
| { |
| LOG_DBG("ON_ACTION initiated"); |
| } |
| else if (aAction == PWMDevice::OFF_ACTION) |
| { |
| LOG_DBG("OFF_ACTION initiated"); |
| } |
| else if (aAction == PWMDevice::LEVEL_ACTION) |
| { |
| LOG_DBG("LEVEL_ACTION initiated"); |
| } |
| } |
| |
| void AppTask::ActionCompleted(PWMDevice::Action_t aAction, int32_t aActor) |
| { |
| if (aAction == PWMDevice::ON_ACTION) |
| { |
| LOG_DBG("ON_ACTION completed"); |
| } |
| else if (aAction == PWMDevice::OFF_ACTION) |
| { |
| LOG_DBG("OFF_ACTION completed"); |
| } |
| else if (aAction == PWMDevice::LEVEL_ACTION) |
| { |
| LOG_DBG("LEVEL_ACTION completed"); |
| } |
| |
| if (aActor == AppEvent::kEventType_Button) |
| { |
| sAppTask.UpdateClusterState(); |
| } |
| } |
| |
| void AppTask::UpdateClusterState(void) |
| { |
| bool isTurnedOn = sAppTask.mPwmRgbBlueLed.IsTurnedOn(); |
| |
| // write the new on/off value |
| Protocols::InteractionModel::Status status = Clusters::OnOff::Attributes::OnOff::Set(kExampleEndpointId, isTurnedOn); |
| |
| if (status != Protocols::InteractionModel::Status::Success) |
| { |
| LOG_ERR("Update OnOff fail: %x", to_underlying(status)); |
| } |
| uint8_t setLevel = sAppTask.mPwmRgbBlueLed.GetLevel(); |
| status = Clusters::LevelControl::Attributes::CurrentLevel::Set(kExampleEndpointId, setLevel); |
| if (status != Protocols::InteractionModel::Status::Success) |
| { |
| LOG_ERR("Update CurrentLevel fail: %x", to_underlying(status)); |
| } |
| } |