LightingAppCommandDelegate.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /*
  2. *
  3. * Copyright (c) 2023 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 "LightingAppCommandDelegate.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/software-diagnostics-server/software-diagnostics-server.h>
  23. #include <app/clusters/switch-server/switch-server.h>
  24. #include <app/server/Server.h>
  25. #include <platform/PlatformManager.h>
  26. using namespace chip;
  27. using namespace chip::app;
  28. using namespace chip::app::Clusters;
  29. using namespace chip::DeviceLayer;
  30. LightingAppCommandHandler * LightingAppCommandHandler::FromJSON(const char * json)
  31. {
  32. Json::Reader reader;
  33. Json::Value value;
  34. if (!reader.parse(json, value))
  35. {
  36. ChipLogError(NotSpecified,
  37. "AllClusters App: Error parsing JSON with error %s:", reader.getFormattedErrorMessages().c_str());
  38. return nullptr;
  39. }
  40. if (value.empty() || !value.isObject())
  41. {
  42. ChipLogError(NotSpecified, "AllClusters App: Invalid JSON command received");
  43. return nullptr;
  44. }
  45. if (!value.isMember("Name") || !value["Name"].isString())
  46. {
  47. ChipLogError(NotSpecified, "AllClusters App: Invalid JSON command received: command name is missing");
  48. return nullptr;
  49. }
  50. return Platform::New<LightingAppCommandHandler>(std::move(value));
  51. }
  52. void LightingAppCommandHandler::HandleCommand(intptr_t context)
  53. {
  54. auto * self = reinterpret_cast<LightingAppCommandHandler *>(context);
  55. std::string name = self->mJsonValue["Name"].asString();
  56. VerifyOrExit(!self->mJsonValue.empty(), ChipLogError(NotSpecified, "Invalid JSON event command received"));
  57. if (name == "SoftwareFault")
  58. {
  59. self->OnSoftwareFaultEventHandler(Clusters::SoftwareDiagnostics::Events::SoftwareFault::Id);
  60. }
  61. else if (name == "HardwareFaultChange")
  62. {
  63. self->OnGeneralFaultEventHandler(Clusters::GeneralDiagnostics::Events::HardwareFaultChange::Id);
  64. }
  65. else if (name == "RadioFaultChange")
  66. {
  67. self->OnGeneralFaultEventHandler(Clusters::GeneralDiagnostics::Events::RadioFaultChange::Id);
  68. }
  69. else if (name == "NetworkFaultChange")
  70. {
  71. self->OnGeneralFaultEventHandler(Clusters::GeneralDiagnostics::Events::NetworkFaultChange::Id);
  72. }
  73. else if (name == "SwitchLatched")
  74. {
  75. uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
  76. self->OnSwitchLatchedHandler(newPosition);
  77. }
  78. else if (name == "InitialPress")
  79. {
  80. uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
  81. self->OnSwitchInitialPressedHandler(newPosition);
  82. }
  83. else if (name == "LongPress")
  84. {
  85. uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
  86. self->OnSwitchLongPressedHandler(newPosition);
  87. }
  88. else if (name == "ShortRelease")
  89. {
  90. uint8_t previousPosition = static_cast<uint8_t>(self->mJsonValue["PreviousPosition"].asUInt());
  91. self->OnSwitchShortReleasedHandler(previousPosition);
  92. }
  93. else if (name == "LongRelease")
  94. {
  95. uint8_t previousPosition = static_cast<uint8_t>(self->mJsonValue["PreviousPosition"].asUInt());
  96. self->OnSwitchLongReleasedHandler(previousPosition);
  97. }
  98. else if (name == "MultiPressOngoing")
  99. {
  100. uint8_t newPosition = static_cast<uint8_t>(self->mJsonValue["NewPosition"].asUInt());
  101. uint8_t count = static_cast<uint8_t>(self->mJsonValue["CurrentNumberOfPressesCounted"].asUInt());
  102. self->OnSwitchMultiPressOngoingHandler(newPosition, count);
  103. }
  104. else if (name == "MultiPressComplete")
  105. {
  106. uint8_t previousPosition = static_cast<uint8_t>(self->mJsonValue["PreviousPosition"].asUInt());
  107. uint8_t count = static_cast<uint8_t>(self->mJsonValue["TotalNumberOfPressesCounted"].asUInt());
  108. self->OnSwitchMultiPressCompleteHandler(previousPosition, count);
  109. }
  110. else if (name == "PowerOnReboot")
  111. {
  112. self->OnRebootSignalHandler(BootReasonType::kPowerOnReboot);
  113. }
  114. else if (name == "BrownOutReset")
  115. {
  116. self->OnRebootSignalHandler(BootReasonType::kBrownOutReset);
  117. }
  118. else if (name == "SoftwareWatchdogReset")
  119. {
  120. self->OnRebootSignalHandler(BootReasonType::kSoftwareWatchdogReset);
  121. }
  122. else if (name == "HardwareWatchdogReset")
  123. {
  124. self->OnRebootSignalHandler(BootReasonType::kHardwareWatchdogReset);
  125. }
  126. else if (name == "SoftwareUpdateCompleted")
  127. {
  128. self->OnRebootSignalHandler(BootReasonType::kSoftwareUpdateCompleted);
  129. }
  130. else if (name == "SoftwareReset")
  131. {
  132. self->OnRebootSignalHandler(BootReasonType::kSoftwareReset);
  133. }
  134. else
  135. {
  136. ChipLogError(NotSpecified, "Unhandled command: Should never happens");
  137. }
  138. exit:
  139. Platform::Delete(self);
  140. }
  141. bool LightingAppCommandHandler::IsClusterPresentOnAnyEndpoint(ClusterId clusterId)
  142. {
  143. EnabledEndpointsWithServerCluster enabledEndpoints(clusterId);
  144. return (enabledEndpoints.begin() != enabledEndpoints.end());
  145. }
  146. void LightingAppCommandHandler::OnRebootSignalHandler(BootReasonType bootReason)
  147. {
  148. if (ConfigurationMgr().StoreBootReason(static_cast<uint32_t>(bootReason)) == CHIP_NO_ERROR)
  149. {
  150. Server::GetInstance().GenerateShutDownEvent();
  151. PlatformMgr().ScheduleWork([](intptr_t) { PlatformMgr().StopEventLoopTask(); });
  152. }
  153. else
  154. {
  155. ChipLogError(NotSpecified, "Failed to store boot reason:%d", static_cast<uint32_t>(bootReason));
  156. }
  157. }
  158. void LightingAppCommandHandler::OnGeneralFaultEventHandler(uint32_t eventId)
  159. {
  160. if (!IsClusterPresentOnAnyEndpoint(Clusters::GeneralDiagnostics::Id))
  161. return;
  162. if (eventId == Clusters::GeneralDiagnostics::Events::HardwareFaultChange::Id)
  163. {
  164. GeneralFaults<kMaxHardwareFaults> previous;
  165. GeneralFaults<kMaxHardwareFaults> current;
  166. using GeneralDiagnostics::HardwareFaultEnum;
  167. // On Linux Simulation, set following hardware faults statically.
  168. ReturnOnFailure(previous.add(to_underlying(HardwareFaultEnum::kRadio)));
  169. ReturnOnFailure(previous.add(to_underlying(HardwareFaultEnum::kPowerSource)));
  170. ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kRadio)));
  171. ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kSensor)));
  172. ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kPowerSource)));
  173. ReturnOnFailure(current.add(to_underlying(HardwareFaultEnum::kUserInterfaceFault)));
  174. Clusters::GeneralDiagnosticsServer::Instance().OnHardwareFaultsDetect(previous, current);
  175. }
  176. else if (eventId == Clusters::GeneralDiagnostics::Events::RadioFaultChange::Id)
  177. {
  178. GeneralFaults<kMaxRadioFaults> previous;
  179. GeneralFaults<kMaxRadioFaults> current;
  180. // On Linux Simulation, set following radio faults statically.
  181. ReturnOnFailure(previous.add(EMBER_ZCL_RADIO_FAULT_ENUM_WI_FI_FAULT));
  182. ReturnOnFailure(previous.add(EMBER_ZCL_RADIO_FAULT_ENUM_THREAD_FAULT));
  183. ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_WI_FI_FAULT));
  184. ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_CELLULAR_FAULT));
  185. ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_THREAD_FAULT));
  186. ReturnOnFailure(current.add(EMBER_ZCL_RADIO_FAULT_ENUM_NFC_FAULT));
  187. Clusters::GeneralDiagnosticsServer::Instance().OnRadioFaultsDetect(previous, current);
  188. }
  189. else if (eventId == Clusters::GeneralDiagnostics::Events::NetworkFaultChange::Id)
  190. {
  191. GeneralFaults<kMaxNetworkFaults> previous;
  192. GeneralFaults<kMaxNetworkFaults> current;
  193. // On Linux Simulation, set following radio faults statically.
  194. ReturnOnFailure(previous.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kHardwareFailure)));
  195. ReturnOnFailure(previous.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kNetworkJammed)));
  196. ReturnOnFailure(current.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kHardwareFailure)));
  197. ReturnOnFailure(current.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kNetworkJammed)));
  198. ReturnOnFailure(current.add(to_underlying(Clusters::GeneralDiagnostics::NetworkFaultEnum::kConnectionFailed)));
  199. Clusters::GeneralDiagnosticsServer::Instance().OnNetworkFaultsDetect(previous, current);
  200. }
  201. else
  202. {
  203. ChipLogError(NotSpecified, "Unknow event ID:%d", eventId);
  204. }
  205. }
  206. void LightingAppCommandHandler::OnSoftwareFaultEventHandler(uint32_t eventId)
  207. {
  208. VerifyOrReturn(eventId == Clusters::SoftwareDiagnostics::Events::SoftwareFault::Id,
  209. ChipLogError(NotSpecified, "Unknown software fault event received"));
  210. if (!IsClusterPresentOnAnyEndpoint(Clusters::SoftwareDiagnostics::Id))
  211. return;
  212. Clusters::SoftwareDiagnostics::Events::SoftwareFault::Type softwareFault;
  213. char threadName[kMaxThreadNameLength + 1];
  214. softwareFault.id = static_cast<uint64_t>(getpid());
  215. Platform::CopyString(threadName, std::to_string(softwareFault.id).c_str());
  216. softwareFault.name.SetValue(CharSpan::fromCharString(threadName));
  217. std::time_t result = std::time(nullptr);
  218. // Using size of 50 as it is double the expected 25 characters "Www Mmm dd hh:mm:ss yyyy\n".
  219. char timeChar[50];
  220. if (std::strftime(timeChar, sizeof(timeChar), "%c", std::localtime(&result)))
  221. {
  222. softwareFault.faultRecording.SetValue(ByteSpan(Uint8::from_const_char(timeChar), strlen(timeChar)));
  223. }
  224. Clusters::SoftwareDiagnosticsServer::Instance().OnSoftwareFaultDetect(softwareFault);
  225. }
  226. void LightingAppCommandHandler::OnSwitchLatchedHandler(uint8_t newPosition)
  227. {
  228. EndpointId endpoint = 0;
  229. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
  230. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
  231. ChipLogDetail(NotSpecified, "The latching switch is moved to a new position:%d", newPosition);
  232. Clusters::SwitchServer::Instance().OnSwitchLatch(endpoint, newPosition);
  233. }
  234. void LightingAppCommandHandler::OnSwitchInitialPressedHandler(uint8_t newPosition)
  235. {
  236. EndpointId endpoint = 0;
  237. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
  238. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
  239. ChipLogDetail(NotSpecified, "The new position when the momentary switch starts to be pressed:%d", newPosition);
  240. Clusters::SwitchServer::Instance().OnInitialPress(endpoint, newPosition);
  241. }
  242. void LightingAppCommandHandler::OnSwitchLongPressedHandler(uint8_t newPosition)
  243. {
  244. EndpointId endpoint = 0;
  245. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
  246. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
  247. ChipLogDetail(NotSpecified, "The new position when the momentary switch has been pressed for a long time:%d", newPosition);
  248. Clusters::SwitchServer::Instance().OnLongPress(endpoint, newPosition);
  249. }
  250. void LightingAppCommandHandler::OnSwitchShortReleasedHandler(uint8_t previousPosition)
  251. {
  252. EndpointId endpoint = 0;
  253. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, 0);
  254. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to reset CurrentPosition attribute"));
  255. ChipLogDetail(NotSpecified, "The the previous value of the CurrentPosition when the momentary switch has been released:%d",
  256. previousPosition);
  257. Clusters::SwitchServer::Instance().OnShortRelease(endpoint, previousPosition);
  258. }
  259. void LightingAppCommandHandler::OnSwitchLongReleasedHandler(uint8_t previousPosition)
  260. {
  261. EndpointId endpoint = 0;
  262. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, 0);
  263. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to reset CurrentPosition attribute"));
  264. ChipLogDetail(NotSpecified,
  265. "The the previous value of the CurrentPosition when the momentary switch has been released after having been "
  266. "pressed for a long time:%d",
  267. previousPosition);
  268. Clusters::SwitchServer::Instance().OnLongRelease(endpoint, previousPosition);
  269. }
  270. void LightingAppCommandHandler::OnSwitchMultiPressOngoingHandler(uint8_t newPosition, uint8_t count)
  271. {
  272. EndpointId endpoint = 0;
  273. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, newPosition);
  274. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set CurrentPosition attribute"));
  275. ChipLogDetail(NotSpecified, "The new position when the momentary switch has been pressed in a multi-press sequence:%d",
  276. newPosition);
  277. ChipLogDetail(NotSpecified, "%d times the momentary switch has been pressed", count);
  278. Clusters::SwitchServer::Instance().OnMultiPressOngoing(endpoint, newPosition, count);
  279. }
  280. void LightingAppCommandHandler::OnSwitchMultiPressCompleteHandler(uint8_t previousPosition, uint8_t count)
  281. {
  282. EndpointId endpoint = 0;
  283. EmberAfStatus status = Switch::Attributes::CurrentPosition::Set(endpoint, 0);
  284. VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to reset CurrentPosition attribute"));
  285. ChipLogDetail(NotSpecified, "The previous position when the momentary switch has been pressed in a multi-press sequence:%d",
  286. previousPosition);
  287. ChipLogDetail(NotSpecified, "%d times the momentary switch has been pressed", count);
  288. Clusters::SwitchServer::Instance().OnMultiPressComplete(endpoint, previousPosition, count);
  289. }
  290. void LightingAppCommandDelegate::OnEventCommandReceived(const char * json)
  291. {
  292. auto handler = LightingAppCommandHandler::FromJSON(json);
  293. if (nullptr == handler)
  294. {
  295. ChipLogError(NotSpecified, "AllClusters App: Unable to instantiate a command handler");
  296. return;
  297. }
  298. chip::DeviceLayer::PlatformMgr().ScheduleWork(LightingAppCommandHandler::HandleCommand, reinterpret_cast<intptr_t>(handler));
  299. }