AllClustersCommandDelegate.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /*
  2. *
  3. * Copyright (c) 2022 Project CHIP Authors
  4. * All rights reserved.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #include "AllClustersCommandDelegate.h"
  19. #include <app-common/zap-generated/attributes/Accessors.h>
  20. #include <app/att-storage.h>
  21. #include <app/clusters/general-diagnostics-server/general-diagnostics-server.h>
  22. #include <app/clusters/smoke-co-alarm-server/smoke-co-alarm-server.h>
  23. #include <app/clusters/software-diagnostics-server/software-diagnostics-server.h>
  24. #include <app/clusters/switch-server/switch-server.h>
  25. #include <app/server/Server.h>
  26. #include <platform/PlatformManager.h>
  27. #include <air-quality-instance.h>
  28. #include <dishwasher-mode.h>
  29. #include <laundry-washer-mode.h>
  30. #include <rvc-modes.h>
  31. using namespace chip;
  32. using namespace chip::app;
  33. using namespace chip::app::Clusters;
  34. using namespace chip::DeviceLayer;
  35. AllClustersAppCommandHandler * AllClustersAppCommandHandler::FromJSON(const char * json)
  36. {
  37. Json::Reader reader;
  38. Json::Value value;
  39. if (!reader.parse(json, value))
  40. {
  41. ChipLogError(NotSpecified,
  42. "AllClusters App: Error parsing JSON with error %s:", reader.getFormattedErrorMessages().c_str());
  43. return nullptr;
  44. }
  45. if (value.empty() || !value.isObject())
  46. {
  47. ChipLogError(NotSpecified, "AllClusters App: Invalid JSON command received");
  48. return nullptr;
  49. }
  50. if (!value.isMember("Name") || !value["Name"].isString())
  51. {
  52. ChipLogError(NotSpecified, "AllClusters App: Invalid JSON command received: command name is missing");
  53. return nullptr;
  54. }
  55. return Platform::New<AllClustersAppCommandHandler>(std::move(value));
  56. }
  57. void AllClustersAppCommandHandler::HandleCommand(intptr_t context)
  58. {
  59. auto * self = reinterpret_cast<AllClustersAppCommandHandler *>(context);
  60. std::string name = self->mJsonValue["Name"].asString();
  61. VerifyOrExit(!self->mJsonValue.empty(), ChipLogError(NotSpecified, "Invalid JSON event command received"));
  62. if (name == "SoftwareFault")
  63. {
  64. self->OnSoftwareFaultEventHandler(Clusters::SoftwareDiagnostics::Events::SoftwareFault::Id);
  65. }
  66. else if (name == "HardwareFaultChange")
  67. {
  68. self->OnGeneralFaultEventHandler(Clusters::GeneralDiagnostics::Events::HardwareFaultChange::Id);
  69. }
  70. else if (name == "RadioFaultChange")
  71. {
  72. self->OnGeneralFaultEventHandler(Clusters::GeneralDiagnostics::Events::RadioFaultChange::Id);
  73. }
  74. else if (name == "NetworkFaultChange")
  75. {
  76. self->OnGeneralFaultEventHandler(Clusters::GeneralDiagnostics::Events::NetworkFaultChange::Id);
  77. }
  78. else if (name == "SwitchLatched")
  79. {
  80. uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
  81. self->OnSwitchLatchedHandler(newPosition);
  82. }
  83. else if (name == "InitialPress")
  84. {
  85. uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
  86. self->OnSwitchInitialPressedHandler(newPosition);
  87. }
  88. else if (name == "LongPress")
  89. {
  90. uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
  91. self->OnSwitchLongPressedHandler(newPosition);
  92. }
  93. else if (name == "ShortRelease")
  94. {
  95. uint8_t previousPosition = static_cast<uint8_t>(self->mJsonValue["PreviousPosition"].asUInt());
  96. self->OnSwitchShortReleasedHandler(previousPosition);
  97. }
  98. else if (name == "LongRelease")
  99. {
  100. uint8_t previousPosition = static_cast<uint8_t>(self->mJsonValue["PreviousPosition"].asUInt());
  101. self->OnSwitchLongReleasedHandler(previousPosition);
  102. }
  103. else if (name == "MultiPressOngoing")
  104. {
  105. uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
  106. uint8_t count = static_cast<uint8_t>(self->mJsonValue["CurrentNumberOfPressesCounted"].asUInt());
  107. self->OnSwitchMultiPressOngoingHandler(newPosition, count);
  108. }
  109. else if (name == "MultiPressComplete")
  110. {
  111. uint8_t previousPosition = static_cast<uint8_t>(self->mJsonValue["PreviousPosition"].asUInt());
  112. uint8_t count = static_cast<uint8_t>(self->mJsonValue["TotalNumberOfPressesCounted"].asUInt());
  113. self->OnSwitchMultiPressCompleteHandler(previousPosition, count);
  114. }
  115. else if (name == "PowerOnReboot")
  116. {
  117. self->OnRebootSignalHandler(BootReasonType::kPowerOnReboot);
  118. }
  119. else if (name == "BrownOutReset")
  120. {
  121. self->OnRebootSignalHandler(BootReasonType::kBrownOutReset);
  122. }
  123. else if (name == "SoftwareWatchdogReset")
  124. {
  125. self->OnRebootSignalHandler(BootReasonType::kSoftwareWatchdogReset);
  126. }
  127. else if (name == "HardwareWatchdogReset")
  128. {
  129. self->OnRebootSignalHandler(BootReasonType::kHardwareWatchdogReset);
  130. }
  131. else if (name == "SoftwareUpdateCompleted")
  132. {
  133. self->OnRebootSignalHandler(BootReasonType::kSoftwareUpdateCompleted);
  134. }
  135. else if (name == "SoftwareReset")
  136. {
  137. self->OnRebootSignalHandler(BootReasonType::kSoftwareReset);
  138. }
  139. else if (name == "ModeChange")
  140. {
  141. using chip::app::DataModel::MakeNullable;
  142. std::string device = self->mJsonValue["Device"].asString();
  143. std::string type = self->mJsonValue["Type"].asString();
  144. Json::Value jsonMode = self->mJsonValue["Mode"];
  145. DataModel::Nullable<uint8_t> mode;
  146. if (!jsonMode.isNull())
  147. {
  148. mode = MakeNullable(static_cast<uint8_t>(jsonMode.asUInt()));
  149. }
  150. else
  151. {
  152. mode.SetNull();
  153. }
  154. self->OnModeChangeHandler(device, type, mode);
  155. }
  156. else if (name == "SetAirQuality")
  157. {
  158. Json::Value jsonAirQualityEnum = self->mJsonValue["NewValue"];
  159. if (jsonAirQualityEnum.isNull())
  160. {
  161. ChipLogError(NotSpecified, "The SetAirQuality command requires the NewValue key.");
  162. }
  163. else
  164. {
  165. self->OnAirQualityChange(static_cast<uint32_t>(jsonAirQualityEnum.asUInt()));
  166. }
  167. }
  168. else
  169. {
  170. ChipLogError(NotSpecified, "Unhandled command: Should never happens");
  171. }
  172. exit:
  173. Platform::Delete(self);
  174. }
  175. bool AllClustersAppCommandHandler::IsClusterPresentOnAnyEndpoint(ClusterId clusterId)
  176. {
  177. EnabledEndpointsWithServerCluster enabledEndpoints(clusterId);
  178. return (enabledEndpoints.begin() != enabledEndpoints.end());
  179. }
  180. void AllClustersAppCommandHandler::OnRebootSignalHandler(BootReasonType bootReason)
  181. {
  182. if (ConfigurationMgr().StoreBootReason(static_cast<uint32_t>(bootReason)) == CHIP_NO_ERROR)
  183. {
  184. Server::GetInstance().GenerateShutDownEvent();
  185. PlatformMgr().ScheduleWork([](intptr_t) { PlatformMgr().StopEventLoopTask(); });
  186. }
  187. else
  188. {
  189. ChipLogError(NotSpecified, "Failed to store boot reason:%d", static_cast<uint32_t>(bootReason));
  190. }
  191. }
  192. void AllClustersAppCommandHandler::OnGeneralFaultEventHandler(uint32_t eventId)
  193. {
  194. if (!IsClusterPresentOnAnyEndpoint(Clusters::GeneralDiagnostics::Id))
  195. return;
  196. if (eventId == Clusters::GeneralDiagnostics::Events::HardwareFaultChange::Id)
  197. {
  198. GeneralFaults<kMaxHardwareFaults> previous;
  199. GeneralFaults<kMaxHardwareFaults> current;
  200. using GeneralDiagnostics::HardwareFaultEnum;
  201. // On Linux Simulation, set following hardware faults statically.
  202. ReturnOnFailure(previous.add(to_underlying(HardwareFaultEnum::kRadio)));
  203. ReturnOnFailure(previous.add(to_underlying(HardwareFaultEnum::kPowerSource)));
  204. ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kRadio)));
  205. ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kSensor)));
  206. ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kPowerSource)));
  207. ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kUserInterfaceFault)));
  208. Clusters::GeneralDiagnosticsServer::Instance().OnHardwareFaultsDetect(previous, current);
  209. }
  210. else if (eventId == Clusters::GeneralDiagnostics::Events::RadioFaultChange::Id)
  211. {
  212. GeneralFaults<kMaxRadioFaults> previous;
  213. GeneralFaults<kMaxRadioFaults> current;
  214. // On Linux Simulation, set following radio faults statically.
  215. ReturnOnFailure(previous.add(EMBER_ZCL_RADIO_FAULT_ENUM_WI_FI_FAULT));
  216. ReturnOnFailure(previous.add(EMBER_ZCL_RADIO_FAULT_ENUM_THREAD_FAULT));
  217. ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_WI_FI_FAULT));
  218. ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_CELLULAR_FAULT));
  219. ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_THREAD_FAULT));
  220. ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_NFC_FAULT));
  221. Clusters::GeneralDiagnosticsServer::Instance().OnRadioFaultsDetect(previous, current);
  222. }
  223. else if (eventId == Clusters::GeneralDiagnostics::Events::NetworkFaultChange::Id)
  224. {
  225. GeneralFaults<kMaxNetworkFaults> previous;
  226. GeneralFaults<kMaxNetworkFaults> current;
  227. // On Linux Simulation, set following radio faults statically.
  228. ReturnOnFailure(previous.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kHardwareFailure)));
  229. ReturnOnFailure(previous.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kNetworkJammed)));
  230. ReturnOnFailure(current.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kHardwareFailure)));
  231. ReturnOnFailure(current.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kNetworkJammed)));
  232. ReturnOnFailure(current.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kConnectionFailed)));
  233. Clusters::GeneralDiagnosticsServer::Instance().OnNetworkFaultsDetect(previous, current);
  234. }
  235. else
  236. {
  237. ChipLogError(NotSpecified, "Unknow event ID:%d", eventId);
  238. }
  239. }
  240. void AllClustersAppCommandHandler::OnSoftwareFaultEventHandler(uint32_t eventId)
  241. {
  242. VerifyOrReturn(eventId == Clusters::SoftwareDiagnostics::Events::SoftwareFault::Id,
  243. ChipLogError(NotSpecified, "Unknown software fault event received"));
  244. if (!IsClusterPresentOnAnyEndpoint(Clusters::SoftwareDiagnostics::Id))
  245. return;
  246. Clusters::SoftwareDiagnostics::Events::SoftwareFault::Type softwareFault;
  247. char threadName[kMaxThreadNameLength + 1];
  248. softwareFault.id = static_cast<uint64_t>(getpid());
  249. Platform::CopyString(threadName, std::to_string(softwareFault.id).c_str());
  250. softwareFault.name.SetValue(CharSpan::fromCharString(threadName));
  251. std::time_t result = std::time(nullptr);
  252. // Using size of 50 as it is double the expected 25 characters "Www Mmm dd hh:mm:ss yyyy\n".
  253. char timeChar[50];
  254. if (std::strftime(timeChar, sizeof(timeChar), "%c", std::localtime(&result)))
  255. {
  256. softwareFault.faultRecording.SetValue(ByteSpan(Uint8::from_const_char(timeChar), strlen(timeChar)));
  257. }
  258. Clusters::SoftwareDiagnosticsServer::Instance().OnSoftwareFaultDetect(softwareFault);
  259. }
  260. void AllClustersAppCommandHandler::OnSwitchLatchedHandler(uint8_t newPosition)
  261. {
  262. EndpointId endpoint = 1;
  263. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
  264. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
  265. ChipLogDetail(NotSpecified, "The latching switch is moved to a new position:%d", newPosition);
  266. Clusters::SwitchServer::Instance().OnSwitchLatch(endpoint, newPosition);
  267. }
  268. void AllClustersAppCommandHandler::OnSwitchInitialPressedHandler(uint8_t newPosition)
  269. {
  270. EndpointId endpoint = 1;
  271. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
  272. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
  273. ChipLogDetail(NotSpecified, "The new position when the momentary switch starts to be pressed:%d", newPosition);
  274. Clusters::SwitchServer::Instance().OnInitialPress(endpoint, newPosition);
  275. }
  276. void AllClustersAppCommandHandler::OnSwitchLongPressedHandler(uint8_t newPosition)
  277. {
  278. EndpointId endpoint = 1;
  279. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
  280. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
  281. ChipLogDetail(NotSpecified, "The new position when the momentary switch has been pressed for a long time:%d", newPosition);
  282. Clusters::SwitchServer::Instance().OnLongPress(endpoint, newPosition);
  283. // Long press to trigger smokeco self-test
  284. SmokeCoAlarmServer::Instance().RequestSelfTest(endpoint);
  285. }
  286. void AllClustersAppCommandHandler::OnSwitchShortReleasedHandler(uint8_t previousPosition)
  287. {
  288. EndpointId endpoint = 1;
  289. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, 0);
  290. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to reset CurrentPosition attribute"));
  291. ChipLogDetail(NotSpecified, "The the previous value of the CurrentPosition when the momentary switch has been released:%d",
  292. previousPosition);
  293. Clusters::SwitchServer::Instance().OnShortRelease(endpoint, previousPosition);
  294. }
  295. void AllClustersAppCommandHandler::OnSwitchLongReleasedHandler(uint8_t previousPosition)
  296. {
  297. EndpointId endpoint = 1;
  298. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, 0);
  299. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to reset CurrentPosition attribute"));
  300. ChipLogDetail(NotSpecified,
  301. "The the previous value of the CurrentPosition when the momentary switch has been released after having been "
  302. "pressed for a long time:%d",
  303. previousPosition);
  304. Clusters::SwitchServer::Instance().OnLongRelease(endpoint, previousPosition);
  305. }
  306. void AllClustersAppCommandHandler::OnSwitchMultiPressOngoingHandler(uint8_t newPosition, uint8_t count)
  307. {
  308. EndpointId endpoint = 1;
  309. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
  310. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
  311. ChipLogDetail(NotSpecified, "The new position when the momentary switch has been pressed in a multi-press sequence:%d",
  312. newPosition);
  313. ChipLogDetail(NotSpecified, "%d times the momentary switch has been pressed", count);
  314. Clusters::SwitchServer::Instance().OnMultiPressOngoing(endpoint, newPosition, count);
  315. }
  316. void AllClustersAppCommandHandler::OnSwitchMultiPressCompleteHandler(uint8_t previousPosition, uint8_t count)
  317. {
  318. EndpointId endpoint = 1;
  319. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, 0);
  320. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to reset CurrentPosition attribute"));
  321. ChipLogDetail(NotSpecified, "The previous position when the momentary switch has been pressed in a multi-press sequence:%d",
  322. previousPosition);
  323. ChipLogDetail(NotSpecified, "%d times the momentary switch has been pressed", count);
  324. Clusters::SwitchServer::Instance().OnMultiPressComplete(endpoint, previousPosition, count);
  325. }
  326. void AllClustersAppCommandHandler::OnModeChangeHandler(std::string device, std::string type, DataModel::Nullable<uint8_t> mode)
  327. {
  328. ModeBase::Instance * modeInstance = nullptr;
  329. if (device == "DishWasher")
  330. {
  331. modeInstance = DishwasherMode::Instance();
  332. }
  333. else if (device == "LaundryWasher")
  334. {
  335. modeInstance = LaundryWasherMode::Instance();
  336. }
  337. else if (device == "RvcClean")
  338. {
  339. modeInstance = RvcCleanMode::Instance();
  340. }
  341. else if (device == "RvcRun")
  342. {
  343. modeInstance = RvcRunMode::Instance();
  344. }
  345. else
  346. {
  347. ChipLogDetail(NotSpecified, "Invalid device type : %s", device.c_str());
  348. return;
  349. }
  350. if (type == "Current")
  351. {
  352. if (mode.IsNull())
  353. {
  354. ChipLogDetail(NotSpecified, "Invalid value : null");
  355. return;
  356. }
  357. modeInstance->UpdateCurrentMode(mode.Value());
  358. }
  359. else if (type == "StartUp")
  360. {
  361. modeInstance->UpdateStartUpMode(mode);
  362. }
  363. else if (type == "On")
  364. {
  365. modeInstance->UpdateOnMode(mode);
  366. }
  367. else
  368. {
  369. ChipLogDetail(NotSpecified, "Invalid mode type : %s", type.c_str());
  370. return;
  371. }
  372. }
  373. void AllClustersAppCommandHandler::OnAirQualityChange(uint32_t aNewValue)
  374. {
  375. AirQuality::Instance * airQualityInstance = AirQuality::GetInstance();
  376. Protocols::InteractionModel::Status status =
  377. airQualityInstance->UpdateAirQuality(static_cast<AirQuality::AirQualityEnum>(aNewValue));
  378. if (status != Protocols::InteractionModel::Status::Success)
  379. {
  380. ChipLogDetail(NotSpecified, "Invalid value: %u", aNewValue);
  381. }
  382. }
  383. void AllClustersCommandDelegate::OnEventCommandReceived(const char * json)
  384. {
  385. auto handler = AllClustersAppCommandHandler::FromJSON(json);
  386. if (nullptr == handler)
  387. {
  388. ChipLogError(NotSpecified, "AllClusters App: Unable to instantiate a command handler");
  389. return;
  390. }
  391. chip::DeviceLayer::PlatformMgr().ScheduleWork(AllClustersAppCommandHandler::HandleCommand, reinterpret_cast<intptr_t>(handler));
  392. }