Device.cpp 8.1 KB

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