| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- /*
- *
- * Copyright (c) 2022 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 "AllClustersCommandDelegate.h"
- #include <app-common/zap-generated/attributes/Accessors.h>
- #include <app/att-storage.h>
- #include <app/clusters/general-diagnostics-server/general-diagnostics-server.h>
- #include <app/clusters/smoke-co-alarm-server/smoke-co-alarm-server.h>
- #include <app/clusters/software-diagnostics-server/software-diagnostics-server.h>
- #include <app/clusters/switch-server/switch-server.h>
- #include <app/server/Server.h>
- #include <platform/PlatformManager.h>
- #include <air-quality-instance.h>
- #include <dishwasher-mode.h>
- #include <laundry-washer-mode.h>
- #include <rvc-modes.h>
- using namespace chip;
- using namespace chip::app;
- using namespace chip::app::Clusters;
- using namespace chip::DeviceLayer;
- AllClustersAppCommandHandler * AllClustersAppCommandHandler::FromJSON(const char * json)
- {
- Json::Reader reader;
- Json::Value value;
- if (!reader.parse(json, value))
- {
- ChipLogError(NotSpecified,
- "AllClusters App: Error parsing JSON with error %s:", reader.getFormattedErrorMessages().c_str());
- return nullptr;
- }
- if (value.empty() || !value.isObject())
- {
- ChipLogError(NotSpecified, "AllClusters App: Invalid JSON command received");
- return nullptr;
- }
- if (!value.isMember("Name") || !value["Name"].isString())
- {
- ChipLogError(NotSpecified, "AllClusters App: Invalid JSON command received: command name is missing");
- return nullptr;
- }
- return Platform::New<AllClustersAppCommandHandler>(std::move(value));
- }
- void AllClustersAppCommandHandler::HandleCommand(intptr_t context)
- {
- auto * self = reinterpret_cast<AllClustersAppCommandHandler *>(context);
- std::string name = self->mJsonValue["Name"].asString();
- VerifyOrExit(!self->mJsonValue.empty(), ChipLogError(NotSpecified, "Invalid JSON event command received"));
- if (name == "SoftwareFault")
- {
- self->OnSoftwareFaultEventHandler(Clusters::SoftwareDiagnostics::Events::SoftwareFault::Id);
- }
- else if (name == "HardwareFaultChange")
- {
- self->OnGeneralFaultEventHandler(Clusters::GeneralDiagnostics::Events::HardwareFaultChange::Id);
- }
- else if (name == "RadioFaultChange")
- {
- self->OnGeneralFaultEventHandler(Clusters::GeneralDiagnostics::Events::RadioFaultChange::Id);
- }
- else if (name == "NetworkFaultChange")
- {
- self->OnGeneralFaultEventHandler(Clusters::GeneralDiagnostics::Events::NetworkFaultChange::Id);
- }
- else if (name == "SwitchLatched")
- {
- uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
- self->OnSwitchLatchedHandler(newPosition);
- }
- else if (name == "InitialPress")
- {
- uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
- self->OnSwitchInitialPressedHandler(newPosition);
- }
- else if (name == "LongPress")
- {
- uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
- self->OnSwitchLongPressedHandler(newPosition);
- }
- else if (name == "ShortRelease")
- {
- uint8_t previousPosition = static_cast<uint8_t>(self->mJsonValue["PreviousPosition"].asUInt());
- self->OnSwitchShortReleasedHandler(previousPosition);
- }
- else if (name == "LongRelease")
- {
- uint8_t previousPosition = static_cast<uint8_t>(self->mJsonValue["PreviousPosition"].asUInt());
- self->OnSwitchLongReleasedHandler(previousPosition);
- }
- else if (name == "MultiPressOngoing")
- {
- uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
- uint8_t count = static_cast<uint8_t>(self->mJsonValue["CurrentNumberOfPressesCounted"].asUInt());
- self->OnSwitchMultiPressOngoingHandler(newPosition, count);
- }
- else if (name == "MultiPressComplete")
- {
- uint8_t previousPosition = static_cast<uint8_t>(self->mJsonValue["PreviousPosition"].asUInt());
- uint8_t count = static_cast<uint8_t>(self->mJsonValue["TotalNumberOfPressesCounted"].asUInt());
- self->OnSwitchMultiPressCompleteHandler(previousPosition, count);
- }
- else if (name == "PowerOnReboot")
- {
- self->OnRebootSignalHandler(BootReasonType::kPowerOnReboot);
- }
- else if (name == "BrownOutReset")
- {
- self->OnRebootSignalHandler(BootReasonType::kBrownOutReset);
- }
- else if (name == "SoftwareWatchdogReset")
- {
- self->OnRebootSignalHandler(BootReasonType::kSoftwareWatchdogReset);
- }
- else if (name == "HardwareWatchdogReset")
- {
- self->OnRebootSignalHandler(BootReasonType::kHardwareWatchdogReset);
- }
- else if (name == "SoftwareUpdateCompleted")
- {
- self->OnRebootSignalHandler(BootReasonType::kSoftwareUpdateCompleted);
- }
- else if (name == "SoftwareReset")
- {
- self->OnRebootSignalHandler(BootReasonType::kSoftwareReset);
- }
- else if (name == "ModeChange")
- {
- using chip::app::DataModel::MakeNullable;
- std::string device = self->mJsonValue["Device"].asString();
- std::string type = self->mJsonValue["Type"].asString();
- Json::Value jsonMode = self->mJsonValue["Mode"];
- DataModel::Nullable<uint8_t> mode;
- if (!jsonMode.isNull())
- {
- mode = MakeNullable(static_cast<uint8_t>(jsonMode.asUInt()));
- }
- else
- {
- mode.SetNull();
- }
- self->OnModeChangeHandler(device, type, mode);
- }
- else if (name == "SetAirQuality")
- {
- Json::Value jsonAirQualityEnum = self->mJsonValue["NewValue"];
- if (jsonAirQualityEnum.isNull())
- {
- ChipLogError(NotSpecified, "The SetAirQuality command requires the NewValue key.");
- }
- else
- {
- self->OnAirQualityChange(static_cast<uint32_t>(jsonAirQualityEnum.asUInt()));
- }
- }
- else
- {
- ChipLogError(NotSpecified, "Unhandled command: Should never happens");
- }
- exit:
- Platform::Delete(self);
- }
- bool AllClustersAppCommandHandler::IsClusterPresentOnAnyEndpoint(ClusterId clusterId)
- {
- EnabledEndpointsWithServerCluster enabledEndpoints(clusterId);
- return (enabledEndpoints.begin() != enabledEndpoints.end());
- }
- void AllClustersAppCommandHandler::OnRebootSignalHandler(BootReasonType bootReason)
- {
- if (ConfigurationMgr().StoreBootReason(static_cast<uint32_t>(bootReason)) == CHIP_NO_ERROR)
- {
- Server::GetInstance().GenerateShutDownEvent();
- PlatformMgr().ScheduleWork([](intptr_t) { PlatformMgr().StopEventLoopTask(); });
- }
- else
- {
- ChipLogError(NotSpecified, "Failed to store boot reason:%d", static_cast<uint32_t>(bootReason));
- }
- }
- void AllClustersAppCommandHandler::OnGeneralFaultEventHandler(uint32_t eventId)
- {
- if (!IsClusterPresentOnAnyEndpoint(Clusters::GeneralDiagnostics::Id))
- return;
- if (eventId == Clusters::GeneralDiagnostics::Events::HardwareFaultChange::Id)
- {
- GeneralFaults<kMaxHardwareFaults> previous;
- GeneralFaults<kMaxHardwareFaults> current;
- using GeneralDiagnostics::HardwareFaultEnum;
- // On Linux Simulation, set following hardware faults statically.
- ReturnOnFailure(previous.add(to_underlying(HardwareFaultEnum::kRadio)));
- ReturnOnFailure(previous.add(to_underlying(HardwareFaultEnum::kPowerSource)));
- ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kRadio)));
- ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kSensor)));
- ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kPowerSource)));
- ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kUserInterfaceFault)));
- Clusters::GeneralDiagnosticsServer::Instance().OnHardwareFaultsDetect(previous, current);
- }
- else if (eventId == Clusters::GeneralDiagnostics::Events::RadioFaultChange::Id)
- {
- GeneralFaults<kMaxRadioFaults> previous;
- GeneralFaults<kMaxRadioFaults> current;
- // On Linux Simulation, set following radio faults statically.
- ReturnOnFailure(previous.add(EMBER_ZCL_RADIO_FAULT_ENUM_WI_FI_FAULT));
- ReturnOnFailure(previous.add(EMBER_ZCL_RADIO_FAULT_ENUM_THREAD_FAULT));
- ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_WI_FI_FAULT));
- ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_CELLULAR_FAULT));
- ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_THREAD_FAULT));
- ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_NFC_FAULT));
- Clusters::GeneralDiagnosticsServer::Instance().OnRadioFaultsDetect(previous, current);
- }
- else if (eventId == Clusters::GeneralDiagnostics::Events::NetworkFaultChange::Id)
- {
- GeneralFaults<kMaxNetworkFaults> previous;
- GeneralFaults<kMaxNetworkFaults> current;
- // On Linux Simulation, set following radio faults statically.
- ReturnOnFailure(previous.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kHardwareFailure)));
- ReturnOnFailure(previous.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kNetworkJammed)));
- ReturnOnFailure(current.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kHardwareFailure)));
- ReturnOnFailure(current.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kNetworkJammed)));
- ReturnOnFailure(current.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kConnectionFailed)));
- Clusters::GeneralDiagnosticsServer::Instance().OnNetworkFaultsDetect(previous, current);
- }
- else
- {
- ChipLogError(NotSpecified, "Unknow event ID:%d", eventId);
- }
- }
- void AllClustersAppCommandHandler::OnSoftwareFaultEventHandler(uint32_t eventId)
- {
- VerifyOrReturn(eventId == Clusters::SoftwareDiagnostics::Events::SoftwareFault::Id,
- ChipLogError(NotSpecified, "Unknown software fault event received"));
- if (!IsClusterPresentOnAnyEndpoint(Clusters::SoftwareDiagnostics::Id))
- return;
- Clusters::SoftwareDiagnostics::Events::SoftwareFault::Type softwareFault;
- char threadName[kMaxThreadNameLength + 1];
- softwareFault.id = static_cast<uint64_t>(getpid());
- Platform::CopyString(threadName, std::to_string(softwareFault.id).c_str());
- softwareFault.name.SetValue(CharSpan::fromCharString(threadName));
- std::time_t result = std::time(nullptr);
- // Using size of 50 as it is double the expected 25 characters "Www Mmm dd hh:mm:ss yyyy\n".
- char timeChar[50];
- if (std::strftime(timeChar, sizeof(timeChar), "%c", std::localtime(&result)))
- {
- softwareFault.faultRecording.SetValue(ByteSpan(Uint8::from_const_char(timeChar), strlen(timeChar)));
- }
- Clusters::SoftwareDiagnosticsServer::Instance().OnSoftwareFaultDetect(softwareFault);
- }
- void AllClustersAppCommandHandler::OnSwitchLatchedHandler(uint8_t newPosition)
- {
- EndpointId endpoint = 1;
- EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
- VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
- ChipLogDetail(NotSpecified, "The latching switch is moved to a new position:%d", newPosition);
- Clusters::SwitchServer::Instance().OnSwitchLatch(endpoint, newPosition);
- }
- void AllClustersAppCommandHandler::OnSwitchInitialPressedHandler(uint8_t newPosition)
- {
- EndpointId endpoint = 1;
- EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
- VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
- ChipLogDetail(NotSpecified, "The new position when the momentary switch starts to be pressed:%d", newPosition);
- Clusters::SwitchServer::Instance().OnInitialPress(endpoint, newPosition);
- }
- void AllClustersAppCommandHandler::OnSwitchLongPressedHandler(uint8_t newPosition)
- {
- EndpointId endpoint = 1;
- EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
- VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
- ChipLogDetail(NotSpecified, "The new position when the momentary switch has been pressed for a long time:%d", newPosition);
- Clusters::SwitchServer::Instance().OnLongPress(endpoint, newPosition);
- // Long press to trigger smokeco self-test
- SmokeCoAlarmServer::Instance().RequestSelfTest(endpoint);
- }
- void AllClustersAppCommandHandler::OnSwitchShortReleasedHandler(uint8_t previousPosition)
- {
- EndpointId endpoint = 1;
- EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, 0);
- VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to reset CurrentPosition attribute"));
- ChipLogDetail(NotSpecified, "The the previous value of the CurrentPosition when the momentary switch has been released:%d",
- previousPosition);
- Clusters::SwitchServer::Instance().OnShortRelease(endpoint, previousPosition);
- }
- void AllClustersAppCommandHandler::OnSwitchLongReleasedHandler(uint8_t previousPosition)
- {
- EndpointId endpoint = 1;
- EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, 0);
- VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to reset CurrentPosition attribute"));
- ChipLogDetail(NotSpecified,
- "The the previous value of the CurrentPosition when the momentary switch has been released after having been "
- "pressed for a long time:%d",
- previousPosition);
- Clusters::SwitchServer::Instance().OnLongRelease(endpoint, previousPosition);
- }
- void AllClustersAppCommandHandler::OnSwitchMultiPressOngoingHandler(uint8_t newPosition, uint8_t count)
- {
- EndpointId endpoint = 1;
- EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
- VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
- ChipLogDetail(NotSpecified, "The new position when the momentary switch has been pressed in a multi-press sequence:%d",
- newPosition);
- ChipLogDetail(NotSpecified, "%d times the momentary switch has been pressed", count);
- Clusters::SwitchServer::Instance().OnMultiPressOngoing(endpoint, newPosition, count);
- }
- void AllClustersAppCommandHandler::OnSwitchMultiPressCompleteHandler(uint8_t previousPosition, uint8_t count)
- {
- EndpointId endpoint = 1;
- EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, 0);
- VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to reset CurrentPosition attribute"));
- ChipLogDetail(NotSpecified, "The previous position when the momentary switch has been pressed in a multi-press sequence:%d",
- previousPosition);
- ChipLogDetail(NotSpecified, "%d times the momentary switch has been pressed", count);
- Clusters::SwitchServer::Instance().OnMultiPressComplete(endpoint, previousPosition, count);
- }
- void AllClustersAppCommandHandler::OnModeChangeHandler(std::string device, std::string type, DataModel::Nullable<uint8_t> mode)
- {
- ModeBase::Instance * modeInstance = nullptr;
- if (device == "DishWasher")
- {
- modeInstance = DishwasherMode::Instance();
- }
- else if (device == "LaundryWasher")
- {
- modeInstance = LaundryWasherMode::Instance();
- }
- else if (device == "RvcClean")
- {
- modeInstance = RvcCleanMode::Instance();
- }
- else if (device == "RvcRun")
- {
- modeInstance = RvcRunMode::Instance();
- }
- else
- {
- ChipLogDetail(NotSpecified, "Invalid device type : %s", device.c_str());
- return;
- }
- if (type == "Current")
- {
- if (mode.IsNull())
- {
- ChipLogDetail(NotSpecified, "Invalid value : null");
- return;
- }
- modeInstance->UpdateCurrentMode(mode.Value());
- }
- else if (type == "StartUp")
- {
- modeInstance->UpdateStartUpMode(mode);
- }
- else if (type == "On")
- {
- modeInstance->UpdateOnMode(mode);
- }
- else
- {
- ChipLogDetail(NotSpecified, "Invalid mode type : %s", type.c_str());
- return;
- }
- }
- void AllClustersAppCommandHandler::OnAirQualityChange(uint32_t aNewValue)
- {
- AirQuality::Instance * airQualityInstance = AirQuality::GetInstance();
- Protocols::InteractionModel::Status status =
- airQualityInstance->UpdateAirQuality(static_cast<AirQuality::AirQualityEnum>(aNewValue));
- if (status != Protocols::InteractionModel::Status::Success)
- {
- ChipLogDetail(NotSpecified, "Invalid value: %u", aNewValue);
- }
- }
- void AllClustersCommandDelegate::OnEventCommandReceived(const char * json)
- {
- auto handler = AllClustersAppCommandHandler::FromJSON(json);
- if (nullptr == handler)
- {
- ChipLogError(NotSpecified, "AllClusters App: Unable to instantiate a command handler");
- return;
- }
- chip::DeviceLayer::PlatformMgr().ScheduleWork(AllClustersAppCommandHandler::HandleCommand, reinterpret_cast<intptr_t>(handler));
- }
|