Device.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. #include <algorithm>
  2. #include <sstream>
  3. #include "Util/JSON.h"
  4. #include "Util/Logger.h"
  5. #include "Device.h"
  6. namespace PresenceDetection {
  7. namespace UniFi {
  8. Device::Device(const std::string& hostname, int port, const std::string& username, const std::string& password, const std::string& cookieFile, int timeout, const std::string& inventoryURL, const std::string& target, const std::vector<Util::Device>& devices) :
  9. m_loggedIn(false),
  10. m_hostname(hostname),
  11. m_port(port),
  12. m_username(username),
  13. m_password(password),
  14. m_cookieFile(cookieFile),
  15. m_timeout(timeout),
  16. m_inventoryURL(inventoryURL),
  17. m_target(target),
  18. m_staticDevices(devices)
  19. {
  20. if (!m_inventoryURL.empty())
  21. UpdateDevicesFromInventory();
  22. ClearDevices();
  23. Start();
  24. }
  25. Device::~Device()
  26. {
  27. Logout();
  28. }
  29. void Device::Start()
  30. {
  31. m_deviceTimer.StartContinuous(5000, static_cast<std::function<void()>>(std::bind(&Device::UpdatePresentDevices, this)));
  32. if (!m_inventoryURL.empty())
  33. m_inventoryTimer.StartContinuous(300000, static_cast<std::function<void()>>(std::bind(&Device::UpdateDevicesFromInventory, this)));
  34. }
  35. void Device::Stop()
  36. {
  37. m_deviceTimer.Stop();
  38. if (!m_inventoryURL.empty())
  39. m_inventoryTimer.Stop();
  40. }
  41. void Device::Wait()
  42. {
  43. m_deviceTimer.Wait();
  44. if (!m_inventoryURL.empty())
  45. m_inventoryTimer.Stop();
  46. }
  47. bool Device::Login()
  48. {
  49. std::stringstream url;
  50. url << "https://" << m_hostname << ":" << m_port << "/api/login";
  51. Util::JSON json;
  52. json["password"] = m_password;
  53. json["username"] = m_username;
  54. try
  55. {
  56. std::stringstream output;
  57. output << m_httpClient.GetUrlPostContents(url.str(), m_cookieFile, json.dump(), "application/json");
  58. Util::JSON outputJSON = Util::JSON::parse(output);
  59. if (outputJSON["meta"]["rc"] != "ok")
  60. {
  61. std::stringstream error;
  62. error << "Login Failed - " << output.str();
  63. throw std::runtime_error(error.str());
  64. }
  65. }
  66. catch (const std::exception& e)
  67. {
  68. std::stringstream ss;
  69. ss << "UniFi::Device::Login() - Error: " << e.what() << std::endl;
  70. Util::Logger::Log(Util::Logger::Severity::Error, ss.str());
  71. std::lock_guard<std::mutex> lock(m_mutex);
  72. m_loggedIn = false;
  73. return m_loggedIn;
  74. }
  75. std::lock_guard<std::mutex> lock(m_mutex);
  76. m_loggedIn = true;
  77. return m_loggedIn;
  78. }
  79. void Device::Logout()
  80. {
  81. std::stringstream url;
  82. url << "https://" << m_hostname << ":" << m_port << "/logout";
  83. std::lock_guard<std::mutex> lock(m_mutex);
  84. m_loggedIn = false;
  85. try
  86. {
  87. m_httpClient.GetUrlSilent(url.str(), m_cookieFile);
  88. }
  89. catch (const std::exception& e)
  90. {
  91. std::stringstream ss;
  92. ss << "UniFi::Device::Logout() - Error: " << e.what() << std::endl;
  93. Util::Logger::Log(Util::Logger::Severity::Error, ss.str());
  94. }
  95. }
  96. void Device::ClearDevices()
  97. {
  98. for (std::vector<std::string>::iterator it = m_devices.begin(); it != m_devices.end(); ++it)
  99. {
  100. try
  101. {
  102. SendStateChange(false, *it);
  103. }
  104. catch (const std::exception& e)
  105. {
  106. std::stringstream ss;
  107. ss << "UniFi::Device::ClearDevices() - Error: " << e.what() << std::endl;
  108. Util::Logger::Log(Util::Logger::Severity::Error, ss.str());
  109. }
  110. }
  111. for (std::vector<Util::Device>::iterator it = m_staticDevices.begin(); it != m_staticDevices.end(); ++it)
  112. {
  113. if (it->HasWifiMac())
  114. {
  115. try
  116. {
  117. SendStateChange(false, it->WifiMac());
  118. }
  119. catch (const std::exception& e)
  120. {
  121. std::stringstream ss;
  122. ss << "UniFi::Device::ClearDevices() - Error: " << e.what() << std::endl;
  123. Util::Logger::Log(Util::Logger::Severity::Error, ss.str());
  124. }
  125. }
  126. }
  127. }
  128. void Device::UpdateDevicesFromInventory()
  129. {
  130. try
  131. {
  132. std::string devices = m_httpClient.GetUrlContents(m_inventoryURL);
  133. Util::JSON json = Util::JSON::parse(devices);
  134. m_devices.clear();
  135. for (auto& element : json)
  136. if (element["macaddress"] != "")
  137. {
  138. std::string macAddress = element["macaddress"];
  139. std::transform(macAddress.begin(), macAddress.end(), macAddress.begin(), ::tolower);
  140. m_devices.push_back(macAddress);
  141. }
  142. }
  143. catch (const std::exception& e)
  144. {
  145. std::stringstream ss;
  146. ss << "UniFi::Device::GetDevicesFromInventory() - Error: " << e.what() << std::endl;
  147. Util::Logger::Log(Util::Logger::Severity::Error, ss.str());
  148. }
  149. }
  150. void Device::UpdatePresentDevices()
  151. {
  152. bool loggedIn;
  153. {
  154. std::lock_guard<std::mutex> lock(m_mutex);
  155. loggedIn = m_loggedIn;
  156. }
  157. if (!loggedIn)
  158. if (!Login())
  159. return;
  160. std::stringstream url;
  161. url << "https://" << m_hostname << ":" << m_port << "/api/s/default/stat/sta";
  162. std::time_t timeStamp = std::time(nullptr);
  163. std::vector<std::string> presentDevices;
  164. std::vector<std::string> addedDevices;
  165. std::vector<std::string> removedDevices;
  166. try
  167. {
  168. std::stringstream output;
  169. output << m_httpClient.GetUrlContents(url.str(), m_cookieFile);
  170. Util::JSON json = Util::JSON::parse(output);
  171. if (json["meta"]["rc"] != "ok")
  172. {
  173. std::stringstream error;
  174. error << "Query Failed";
  175. throw std::runtime_error(error.str());
  176. }
  177. for (auto& device : json["data"])
  178. {
  179. std::string macAddress = device["mac"];
  180. std::transform(macAddress.begin(), macAddress.end(), macAddress.begin(), ::tolower);
  181. int lastSeen = device["last_seen"];
  182. if (std::find(m_devices.begin(), m_devices.end(), macAddress) != m_devices.end())
  183. {
  184. if ((timeStamp - lastSeen) < m_timeout)
  185. {
  186. if (std::find(m_presentDevices.begin(), m_presentDevices.end(), macAddress) == m_presentDevices.end())
  187. addedDevices.push_back(macAddress);
  188. presentDevices.push_back(macAddress);
  189. }
  190. }
  191. for (std::vector<Util::Device>::iterator it = m_staticDevices.begin(); it != m_staticDevices.end(); ++it)
  192. {
  193. if ((timeStamp - lastSeen) < m_timeout)
  194. {
  195. if (it->HasWifiMac() && it->WifiMac() == macAddress)
  196. {
  197. if (std::find(m_presentDevices.begin(), m_presentDevices.end(), macAddress) == m_presentDevices.end())
  198. addedDevices.push_back(macAddress);
  199. presentDevices.push_back(macAddress);
  200. }
  201. }
  202. }
  203. }
  204. }
  205. catch (const std::exception& e)
  206. {
  207. std::stringstream ss;
  208. ss << "UniFi::Device::IsDevicePresent() - Error: " << e.what() << std::endl;
  209. Util::Logger::Log(Util::Logger::Severity::Error, ss.str());
  210. Logout();
  211. return;
  212. }
  213. for (std::vector<std::string>::iterator it = m_presentDevices.begin(); it != m_presentDevices.end(); ++it)
  214. if (std::find(presentDevices.begin(), presentDevices.end(), *it) == presentDevices.end())
  215. removedDevices.push_back(*it);
  216. for (std::vector<std::string>::iterator it = addedDevices.begin(); it != addedDevices.end(); ++it)
  217. SendStateChange(true, *it);
  218. for (std::vector<std::string>::iterator it = removedDevices.begin(); it != removedDevices.end(); ++it)
  219. SendStateChange(false, *it);
  220. m_presentDevices.assign(presentDevices.begin(), presentDevices.end());
  221. }
  222. void Device::SendStateChange(bool present, const std::string& macAddress)
  223. {
  224. char sign;
  225. if (present)
  226. sign = '+';
  227. else
  228. sign = '-';
  229. std::stringstream ss;
  230. ss << "UniFi: " << sign << " " << macAddress;
  231. Util::Logger::Log(Util::Logger::Severity::Info, ss.str());
  232. if (!m_target.empty())
  233. {
  234. std::stringstream url;
  235. url << m_target << "/UniFi/" << sign << "/" << macAddress;
  236. try
  237. {
  238. m_httpClient.GetUrlSilent(url.str());
  239. }
  240. catch (const std::exception& e)
  241. {
  242. std::stringstream ss;
  243. ss << "UniFi::Device::SendStateChange() - Error: " << e.what() << std::endl;
  244. Util::Logger::Log(Util::Logger::Severity::Error, ss.str());
  245. }
  246. }
  247. for (std::vector<Util::Device>::iterator it = m_staticDevices.begin(); it != m_staticDevices.end(); ++it)
  248. {
  249. if (it->HasWifiMac() && it->WifiMac() == macAddress)
  250. {
  251. it->SetWifiState(present);
  252. std::vector<std::string> urls;
  253. if (present)
  254. {
  255. if (!it->GetBluetoothState() && it->HasOnlineURL())
  256. urls.push_back(it->OnlineURL());
  257. if (it->HasWifiOnlineURL())
  258. urls.push_back(it->WifiOnlineURL());
  259. }
  260. else if (!present)
  261. {
  262. if (!it->GetBluetoothState() && it->HasOfflineURL())
  263. urls.push_back(it->OfflineURL());
  264. if (it->HasWifiOfflineURL())
  265. urls.push_back(it->WifiOfflineURL());
  266. }
  267. for (auto& url : urls)
  268. {
  269. try
  270. {
  271. m_httpClient.GetUrlSilent(url);
  272. }
  273. catch (const std::exception& e)
  274. {
  275. std::stringstream ss;
  276. ss << "UniFi::Device::SendStateChange() - Error: " << e.what() << std::endl;
  277. Util::Logger::Log(Util::Logger::Severity::Error, ss.str());
  278. }
  279. }
  280. }
  281. }
  282. }
  283. } // namespace UniFi
  284. } // namespace PresenceDetection