Device.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #include <syslog.h>
  2. #include <boost/foreach.hpp>
  3. #include <boost/property_tree/ptree.hpp>
  4. #include <boost/property_tree/json_parser.hpp>
  5. #include "Device.h"
  6. namespace PresenceDetection {
  7. namespace UniFi {
  8. Device::Device(const std::string& hostname, const std::string& username, const std::string& password, const std::string& cookieFile, const std::string& target) :
  9. m_loggedIn(false),
  10. m_hostname(hostname),
  11. m_username(username),
  12. m_password(password),
  13. m_cookieFile(cookieFile),
  14. m_target(target)
  15. {
  16. m_offlineTimeout = 120;
  17. Start();
  18. }
  19. Device::~Device()
  20. {
  21. Logout();
  22. }
  23. void Device::Start()
  24. {
  25. m_timer.StartContinuous(5000, static_cast<std::function<void()>>(std::bind(&Device::UpdatePresentDevices, this)));
  26. }
  27. void Device::Stop()
  28. {
  29. m_timer.Stop();
  30. }
  31. void Device::Wait()
  32. {
  33. m_timer.Wait();
  34. }
  35. bool Device::Login()
  36. {
  37. std::stringstream url;
  38. url << "https://" << m_hostname << "/api/login";
  39. std::ostringstream json;
  40. boost::property_tree::ptree root;
  41. root.put("password", m_password);
  42. root.put("username", m_username);
  43. boost::property_tree::write_json(json, root);
  44. try
  45. {
  46. std::stringstream output;
  47. output << m_httpClient.GetUrlPostContents(url.str(), m_cookieFile, json.str(), "application/json");
  48. boost::property_tree::ptree pt;
  49. boost::property_tree::read_json(output, pt);
  50. std::string result = pt.get_child("meta").get<std::string>("rc");
  51. if (result != "ok")
  52. {
  53. std::stringstream error;
  54. error << "Login Failed - " << output.str();
  55. throw std::runtime_error(error.str());
  56. }
  57. }
  58. catch (const std::exception& e)
  59. {
  60. std::stringstream ss;
  61. ss << "UniFi::Device::Login() - Error: " << e.what() << std::endl;
  62. syslog(LOG_ERR, "%s", ss.str().c_str());
  63. std::lock_guard<std::mutex> lock(m_mutex);
  64. m_loggedIn = false;
  65. return m_loggedIn;
  66. }
  67. std::lock_guard<std::mutex> lock(m_mutex);
  68. m_loggedIn = true;
  69. return m_loggedIn;
  70. }
  71. void Device::Logout()
  72. {
  73. std::stringstream url;
  74. url << "https://" << m_hostname << "/logout";
  75. std::lock_guard<std::mutex> lock(m_mutex);
  76. m_loggedIn = false;
  77. try
  78. {
  79. m_httpClient.GetUrlSilent(url.str(), m_cookieFile);
  80. }
  81. catch (const std::exception& e)
  82. {
  83. std::stringstream ss;
  84. ss << "UniFi::Device::Logout() - Error: " << e.what() << std::endl;
  85. syslog(LOG_ERR, "%s", ss.str().c_str());
  86. }
  87. }
  88. void Device::UpdatePresentDevices()
  89. {
  90. bool loggedIn;
  91. {
  92. std::lock_guard<std::mutex> lock(m_mutex);
  93. loggedIn = m_loggedIn;
  94. }
  95. if (!loggedIn)
  96. if (!Login())
  97. return;
  98. std::stringstream url;
  99. url << "https://" << m_hostname << "/api/s/default/stat/sta";
  100. std::time_t timeStamp = std::time(nullptr);
  101. std::vector<std::string> presentDevices;
  102. std::vector<std::string> addedDevices;
  103. std::vector<std::string> removedDevices;
  104. try
  105. {
  106. std::stringstream output;
  107. output << m_httpClient.GetUrlContents(url.str(), m_cookieFile);
  108. boost::property_tree::ptree pt;
  109. boost::property_tree::read_json(output, pt);
  110. std::string result = pt.get_child("meta").get<std::string>("rc");
  111. if (result != "ok")
  112. {
  113. std::stringstream error;
  114. error << "Query Failed";
  115. throw std::runtime_error(error.str());
  116. }
  117. BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("data"))
  118. {
  119. std::string macAddress = v.second.get<std::string>("mac");
  120. int lastSeen = v.second.get<int>("last_seen");
  121. if ((timeStamp - lastSeen) < m_offlineTimeout)
  122. {
  123. if (std::find(m_presentDevices.begin(), m_presentDevices.end(), macAddress) == m_presentDevices.end())
  124. addedDevices.push_back(macAddress);
  125. presentDevices.push_back(macAddress);
  126. }
  127. }
  128. }
  129. catch (const std::exception& e)
  130. {
  131. std::stringstream ss;
  132. ss << "UniFi::Device::IsDevicePresent() - Error: " << e.what() << std::endl;
  133. syslog(LOG_ERR, "%s", ss.str().c_str());
  134. Logout();
  135. return;
  136. }
  137. for (std::vector<std::string>::iterator it = m_presentDevices.begin(); it != m_presentDevices.end(); ++it)
  138. if (std::find(presentDevices.begin(), presentDevices.end(), *it) == presentDevices.end())
  139. removedDevices.push_back(*it);
  140. for (std::vector<std::string>::iterator it = addedDevices.begin(); it != addedDevices.end(); ++it)
  141. SendStateChange(true, *it);
  142. for (std::vector<std::string>::iterator it = removedDevices.begin(); it != removedDevices.end(); ++it)
  143. SendStateChange(false, *it);
  144. m_presentDevices.assign(presentDevices.begin(), presentDevices.end());
  145. }
  146. void Device::SendStateChange(bool present, const std::string& macAddress)
  147. {
  148. char sign;
  149. if (present)
  150. sign = '+';
  151. else
  152. sign = '-';
  153. std::stringstream ss;
  154. ss << "UniFi: " << sign << " " << macAddress;
  155. syslog(LOG_INFO, "%s", ss.str().c_str());
  156. std::stringstream url;
  157. url << m_target << "/UniFi/" << sign << "/" << macAddress;
  158. try
  159. {
  160. m_httpClient.GetUrlSilent(url.str());
  161. }
  162. catch (const std::exception& e)
  163. {
  164. std::stringstream ss;
  165. ss << "UniFi::Device::SendStateChange() - Error: " << e.what() << std::endl;
  166. syslog(LOG_ERR, "%s", ss.str().c_str());
  167. }
  168. }
  169. } // namespace UniFi
  170. } // namespace PresenceDetection