1 #include "stdafx.h" 2 #include "WebServer.h" 3 #include "WebServerHelper.h" 4 #include <boost/bind.hpp> 5 #include <iostream> 6 #include <fstream> 7 #include "mainworker.h" 8 #include "Helper.h" 9 #include "localtime_r.h" 10 #include "EventSystem.h" 11 #include "HTMLSanitizer.h" 12 #include "dzVents.h" 13 #include "../httpclient/HTTPClient.h" 14 #include "../hardware/hardwaretypes.h" 15 #include "../hardware/1Wire.h" 16 #include "../hardware/OTGWBase.h" 17 #ifdef WITH_OPENZWAVE 18 #include "../hardware/OpenZWave.h" 19 #endif 20 #include "../hardware/EnOceanESP2.h" 21 #include "../hardware/EnOceanESP3.h" 22 #include "../hardware/Wunderground.h" 23 #include "../hardware/DarkSky.h" 24 #include "../hardware/AccuWeather.h" 25 #include "../hardware/OpenWeatherMap.h" 26 #include "../hardware/Buienradar.h" 27 #include "../hardware/Kodi.h" 28 #include "../hardware/Limitless.h" 29 #include "../hardware/LogitechMediaServer.h" 30 #include "../hardware/MySensorsBase.h" 31 #include "../hardware/RFXBase.h" 32 #include "../hardware/RFLinkBase.h" 33 #include "../hardware/SysfsGpio.h" 34 #include "../hardware/HEOS.h" 35 #include "../hardware/eHouseTCP.h" 36 #include "../hardware/USBtin.h" 37 #include "../hardware/USBtin_MultiblocV8.h" 38 #ifdef WITH_GPIO 39 #include "../hardware/Gpio.h" 40 #include "../hardware/GpioPin.h" 41 #endif // WITH_GPIO 42 #include "../hardware/Tellstick.h" 43 #include "../webserver/Base64.h" 44 #include "../smtpclient/SMTPClient.h" 45 #include <json/json.h> 46 #include "../main/json_helper.h" 47 #include "Logger.h" 48 #include "SQLHelper.h" 49 #include "../push/BasePush.h" 50 #include <algorithm> 51 #ifdef ENABLE_PYTHON 52 #include "../hardware/plugins/Plugins.h" 53 #endif 54 55 #ifndef WIN32 56 #include <sys/utsname.h> 57 #include <dirent.h> 58 #else 59 #include "../msbuild/WindowsHelper.h" 60 #include "dirent_windows.h" 61 #endif 62 #include "../notifications/NotificationHelper.h" 63 #include "../main/LuaHandler.h" 64 65 #define __STDC_FORMAT_MACROS 66 #include <inttypes.h> 67 68 #define round(a) ( int ) ( a + .5 ) 69 70 extern std::string szStartupFolder; 71 extern std::string szUserDataFolder; 72 extern std::string szWWWFolder; 73 74 extern std::string szAppVersion; 75 extern std::string szAppHash; 76 extern std::string szAppDate; 77 extern std::string szPyVersion; 78 79 extern bool g_bUseUpdater; 80 81 extern time_t m_StartTime; 82 83 extern bool g_bDontCacheWWW; 84 85 struct _tGuiLanguage { 86 const char* szShort; 87 const char* szLong; 88 }; 89 90 static const _tGuiLanguage guiLanguage[] = 91 { 92 { "en", "English" }, 93 { "sq", "Albanian" }, 94 { "ar", "Arabic" }, 95 { "bs", "Bosnian" }, 96 { "bg", "Bulgarian" }, 97 { "ca", "Catalan" }, 98 { "zh", "Chinese" }, 99 { "cs", "Czech" }, 100 { "da", "Danish" }, 101 { "nl", "Dutch" }, 102 { "et", "Estonian" }, 103 { "de", "German" }, 104 { "el", "Greek" }, 105 { "fr", "French" }, 106 { "fi", "Finnish" }, 107 { "he", "Hebrew" }, 108 { "hu", "Hungarian" }, 109 { "is", "Icelandic" }, 110 { "it", "Italian" }, 111 { "lt", "Lithuanian" }, 112 { "lv", "Latvian" }, 113 { "mk", "Macedonian" }, 114 { "no", "Norwegian" }, 115 { "fa", "Persian" }, 116 { "pl", "Polish" }, 117 { "pt", "Portuguese" }, 118 { "ro", "Romanian" }, 119 { "ru", "Russian" }, 120 { "sr", "Serbian" }, 121 { "sk", "Slovak" }, 122 { "sl", "Slovenian" }, 123 { "es", "Spanish" }, 124 { "sv", "Swedish" }, 125 { "zh_TW", "Taiwanese" }, 126 { "tr", "Turkish" }, 127 { "uk", "Ukrainian" }, 128 { NULL, NULL } 129 }; 130 131 extern http::server::CWebServerHelper m_webservers; 132 133 namespace http { 134 namespace server { 135 CWebServer(void)136 CWebServer::CWebServer(void) : session_store() 137 { 138 m_pWebEm = NULL; 139 m_bDoStop = false; 140 #ifdef WITH_OPENZWAVE 141 m_ZW_Hwidx = -1; 142 #endif 143 } 144 145 ~CWebServer(void)146 CWebServer::~CWebServer(void) 147 { 148 // RK, we call StopServer() instead of just deleting m_pWebEm. The Do_Work thread might still be accessing that object 149 StopServer(); 150 } 151 Do_Work()152 void CWebServer::Do_Work() 153 { 154 bool exception_thrown = false; 155 while (!m_bDoStop) 156 { 157 exception_thrown = false; 158 try { 159 if (m_pWebEm) { 160 m_pWebEm->Run(); 161 } 162 } 163 catch (std::exception& e) { 164 _log.Log(LOG_ERROR, "WebServer(%s) exception occurred : '%s'", m_server_alias.c_str(), e.what()); 165 exception_thrown = true; 166 } 167 catch (...) { 168 _log.Log(LOG_ERROR, "WebServer(%s) unknown exception occurred", m_server_alias.c_str()); 169 exception_thrown = true; 170 } 171 if (exception_thrown) { 172 _log.Log(LOG_STATUS, "WebServer(%s) restart server in 5 seconds", m_server_alias.c_str()); 173 sleep_milliseconds(5000); // prevents from an exception flood 174 continue; 175 } 176 break; 177 } 178 _log.Log(LOG_STATUS, "WebServer(%s) stopped", m_server_alias.c_str()); 179 } 180 ReloadCustomSwitchIcons()181 void CWebServer::ReloadCustomSwitchIcons() 182 { 183 m_custom_light_icons.clear(); 184 m_custom_light_icons_lookup.clear(); 185 std::string sLine = ""; 186 187 //First get them from the switch_icons.txt file 188 std::ifstream infile; 189 std::string switchlightsfile = szWWWFolder + "/switch_icons.txt"; 190 infile.open(switchlightsfile.c_str()); 191 if (infile.is_open()) 192 { 193 int index = 0; 194 while (!infile.eof()) 195 { 196 getline(infile, sLine); 197 if (sLine.size() != 0) 198 { 199 std::vector<std::string> results; 200 StringSplit(sLine, ";", results); 201 if (results.size() == 3) 202 { 203 _tCustomIcon cImage; 204 cImage.idx = index++; 205 cImage.RootFile = results[0]; 206 cImage.Title = results[1]; 207 cImage.Description = results[2]; 208 m_custom_light_icons.push_back(cImage); 209 m_custom_light_icons_lookup[cImage.idx] = m_custom_light_icons.size() - 1; 210 } 211 } 212 } 213 infile.close(); 214 } 215 //Now get them from the database (idx 100+) 216 std::vector<std::vector<std::string> > result; 217 result = m_sql.safe_query("SELECT ID,Base,Name,Description FROM CustomImages"); 218 if (!result.empty()) 219 { 220 int ii = 0; 221 for (const auto & itt : result) 222 { 223 std::vector<std::string> sd = itt; 224 225 int ID = atoi(sd[0].c_str()); 226 227 _tCustomIcon cImage; 228 cImage.idx = 100 + ID; 229 cImage.RootFile = sd[1]; 230 cImage.Title = sd[2]; 231 cImage.Description = sd[3]; 232 233 std::string IconFile16 = cImage.RootFile + ".png"; 234 std::string IconFile48On = cImage.RootFile + "48_On.png"; 235 std::string IconFile48Off = cImage.RootFile + "48_Off.png"; 236 237 std::map<std::string, std::string> _dbImageFiles; 238 _dbImageFiles["IconSmall"] = szWWWFolder + "/images/" + IconFile16; 239 _dbImageFiles["IconOn"] = szWWWFolder + "/images/" + IconFile48On; 240 _dbImageFiles["IconOff"] = szWWWFolder + "/images/" + IconFile48Off; 241 242 //Check if files are on disk, else add them 243 for (const auto & iItt : _dbImageFiles) 244 { 245 std::string TableField = iItt.first; 246 std::string IconFile = iItt.second; 247 248 if (!file_exist(IconFile.c_str())) 249 { 250 //Does not exists, extract it from the database and add it 251 std::vector<std::vector<std::string> > result2; 252 result2 = m_sql.safe_queryBlob("SELECT %s FROM CustomImages WHERE ID=%d", TableField.c_str(), ID); 253 if (!result2.empty()) 254 { 255 std::ofstream file; 256 file.open(IconFile.c_str(), std::ios::out | std::ios::binary); 257 if (!file.is_open()) 258 return; 259 260 file << result2[0][0]; 261 file.close(); 262 } 263 } 264 } 265 266 m_custom_light_icons.push_back(cImage); 267 m_custom_light_icons_lookup[cImage.idx] = m_custom_light_icons.size() - 1; 268 ii++; 269 } 270 } 271 } 272 StartServer(server_settings & settings,const std::string & serverpath,const bool bIgnoreUsernamePassword)273 bool CWebServer::StartServer(server_settings & settings, const std::string & serverpath, const bool bIgnoreUsernamePassword) 274 { 275 m_server_alias = (settings.is_secure() == true) ? "SSL" : "HTTP"; 276 277 if (!settings.is_enabled()) 278 return true; 279 280 ReloadCustomSwitchIcons(); 281 282 int tries = 0; 283 bool exception = false; 284 285 //_log.Log(LOG_STATUS, "CWebServer::StartServer() : settings : %s", settings.to_string().c_str()); 286 do { 287 try { 288 exception = false; 289 m_pWebEm = new http::server::cWebem(settings, serverpath.c_str()); 290 } 291 catch (std::exception& e) { 292 exception = true; 293 switch (tries) { 294 case 0: 295 settings.listening_address = "::"; 296 break; 297 case 1: 298 settings.listening_address = "0.0.0.0"; 299 break; 300 case 2: 301 _log.Log(LOG_ERROR, "WebServer(%s) startup failed on address %s with port: %s: %s", m_server_alias.c_str(), settings.listening_address.c_str(), settings.listening_port.c_str(), e.what()); 302 if (atoi(settings.listening_port.c_str()) < 1024) 303 _log.Log(LOG_ERROR, "WebServer(%s) check privileges for opening ports below 1024", m_server_alias.c_str()); 304 else 305 _log.Log(LOG_ERROR, "WebServer(%s) check if no other application is using port: %s", m_server_alias.c_str(), settings.listening_port.c_str()); 306 return false; 307 } 308 tries++; 309 } 310 } while (exception); 311 312 _log.Log(LOG_STATUS, "WebServer(%s) started on address: %s with port %s", m_server_alias.c_str(), settings.listening_address.c_str(), settings.listening_port.c_str()); 313 314 m_pWebEm->SetDigistRealm("Domoticz.com"); 315 m_pWebEm->SetSessionStore(this); 316 317 if (!bIgnoreUsernamePassword) 318 { 319 LoadUsers(); 320 std::string WebLocalNetworks; 321 int nValue; 322 if (m_sql.GetPreferencesVar("WebLocalNetworks", nValue, WebLocalNetworks)) 323 { 324 std::vector<std::string> strarray; 325 StringSplit(WebLocalNetworks, ";", strarray); 326 for (const auto & itt : strarray) 327 m_pWebEm->AddLocalNetworks(itt); 328 //add local hostname 329 m_pWebEm->AddLocalNetworks(""); 330 } 331 } 332 333 std::string WebRemoteProxyIPs; 334 int nValue; 335 if (m_sql.GetPreferencesVar("WebRemoteProxyIPs", nValue, WebRemoteProxyIPs)) 336 { 337 std::vector<std::string> strarray; 338 StringSplit(WebRemoteProxyIPs, ";", strarray); 339 for (const auto & itt : strarray) 340 m_pWebEm->AddRemoteProxyIPs(itt); 341 } 342 343 //register callbacks 344 m_pWebEm->RegisterIncludeCode("switchtypes", boost::bind(&CWebServer::DisplaySwitchTypesCombo, this, _1)); 345 m_pWebEm->RegisterIncludeCode("metertypes", boost::bind(&CWebServer::DisplayMeterTypesCombo, this, _1)); 346 m_pWebEm->RegisterIncludeCode("timertypes", boost::bind(&CWebServer::DisplayTimerTypesCombo, this, _1)); 347 m_pWebEm->RegisterIncludeCode("combolanguage", boost::bind(&CWebServer::DisplayLanguageCombo, this, _1)); 348 349 m_pWebEm->RegisterPageCode("/json.htm", boost::bind(&CWebServer::GetJSonPage, this, _1, _2, _3)); 350 m_pWebEm->RegisterPageCode("/uploadcustomicon", boost::bind(&CWebServer::Post_UploadCustomIcon, this, _1, _2, _3)); 351 m_pWebEm->RegisterPageCode("/html5.appcache", boost::bind(&CWebServer::GetAppCache, this, _1, _2, _3)); 352 m_pWebEm->RegisterPageCode("/camsnapshot.jpg", boost::bind(&CWebServer::GetCameraSnapshot, this, _1, _2, _3)); 353 m_pWebEm->RegisterPageCode("/backupdatabase.php", boost::bind(&CWebServer::GetDatabaseBackup, this, _1, _2, _3)); 354 m_pWebEm->RegisterPageCode("/raspberry.cgi", boost::bind(&CWebServer::GetInternalCameraSnapshot, this, _1, _2, _3)); 355 m_pWebEm->RegisterPageCode("/uvccapture.cgi", boost::bind(&CWebServer::GetInternalCameraSnapshot, this, _1, _2, _3)); 356 m_pWebEm->RegisterPageCode("/images/floorplans/plan", boost::bind(&CWebServer::GetFloorplanImage, this, _1, _2, _3)); 357 358 m_pWebEm->RegisterPageCode("/storesettings", boost::bind(&CWebServer::PostSettings, this, _1, _2, _3)); 359 m_pWebEm->RegisterActionCode("setrfxcommode", boost::bind(&CWebServer::SetRFXCOMMode, this, _1, _2, _3)); 360 m_pWebEm->RegisterActionCode("rfxupgradefirmware", boost::bind(&CWebServer::RFXComUpgradeFirmware, this, _1, _2, _3)); 361 RegisterCommandCode("rfxfirmwaregetpercentage", boost::bind(&CWebServer::Cmd_RFXComGetFirmwarePercentage, this, _1, _2, _3), true); 362 m_pWebEm->RegisterActionCode("setrego6xxtype", boost::bind(&CWebServer::SetRego6XXType, this, _1, _2, _3)); 363 m_pWebEm->RegisterActionCode("sets0metertype", boost::bind(&CWebServer::SetS0MeterType, this, _1, _2, _3)); 364 m_pWebEm->RegisterActionCode("setlimitlesstype", boost::bind(&CWebServer::SetLimitlessType, this, _1, _2, _3)); 365 366 m_pWebEm->RegisterActionCode("uploadfloorplanimage", boost::bind(&CWebServer::UploadFloorplanImage, this, _1, _2, _3)); 367 368 369 m_pWebEm->RegisterActionCode("setopenthermsettings", boost::bind(&CWebServer::SetOpenThermSettings, this, _1, _2, _3)); 370 RegisterCommandCode("sendopenthermcommand", boost::bind(&CWebServer::Cmd_SendOpenThermCommand, this, _1, _2, _3), true); 371 372 m_pWebEm->RegisterActionCode("reloadpiface", boost::bind(&CWebServer::ReloadPiFace, this, _1, _2, _3)); 373 m_pWebEm->RegisterActionCode("setcurrentcostmetertype", boost::bind(&CWebServer::SetCurrentCostUSBType, this, _1, _2, _3)); 374 m_pWebEm->RegisterActionCode("restoredatabase", boost::bind(&CWebServer::RestoreDatabase, this, _1, _2, _3)); 375 m_pWebEm->RegisterActionCode("sbfspotimportolddata", boost::bind(&CWebServer::SBFSpotImportOldData, this, _1, _2, _3)); 376 377 m_pWebEm->RegisterActionCode("event_create", boost::bind(&CWebServer::EventCreate, this, _1, _2, _3)); 378 379 RegisterCommandCode("getlanguage", boost::bind(&CWebServer::Cmd_GetLanguage, this, _1, _2, _3), true); 380 RegisterCommandCode("getthemes", boost::bind(&CWebServer::Cmd_GetThemes, this, _1, _2, _3), true); 381 RegisterCommandCode("gettitle", boost::bind(&CWebServer::Cmd_GetTitle, this, _1, _2, _3), true); 382 383 RegisterCommandCode("logincheck", boost::bind(&CWebServer::Cmd_LoginCheck, this, _1, _2, _3), true); 384 m_pWebEm->RegisterPageCode("/logincheck", boost::bind(&CWebServer::PostLoginCheck, this, _1, _2, _3), true); 385 386 RegisterCommandCode("getversion", boost::bind(&CWebServer::Cmd_GetVersion, this, _1, _2, _3), true); 387 RegisterCommandCode("getlog", boost::bind(&CWebServer::Cmd_GetLog, this, _1, _2, _3)); 388 RegisterCommandCode("clearlog", boost::bind(&CWebServer::Cmd_ClearLog, this, _1, _2, _3)); 389 RegisterCommandCode("getauth", boost::bind(&CWebServer::Cmd_GetAuth, this, _1, _2, _3), true); 390 RegisterCommandCode("getuptime", boost::bind(&CWebServer::Cmd_GetUptime, this, _1, _2, _3), true); 391 392 393 RegisterCommandCode("gethardwaretypes", boost::bind(&CWebServer::Cmd_GetHardwareTypes, this, _1, _2, _3)); 394 RegisterCommandCode("addhardware", boost::bind(&CWebServer::Cmd_AddHardware, this, _1, _2, _3)); 395 RegisterCommandCode("updatehardware", boost::bind(&CWebServer::Cmd_UpdateHardware, this, _1, _2, _3)); 396 RegisterCommandCode("deletehardware", boost::bind(&CWebServer::Cmd_DeleteHardware, this, _1, _2, _3)); 397 398 RegisterCommandCode("addcamera", boost::bind(&CWebServer::Cmd_AddCamera, this, _1, _2, _3)); 399 RegisterCommandCode("updatecamera", boost::bind(&CWebServer::Cmd_UpdateCamera, this, _1, _2, _3)); 400 RegisterCommandCode("deletecamera", boost::bind(&CWebServer::Cmd_DeleteCamera, this, _1, _2, _3)); 401 402 RegisterCommandCode("wolgetnodes", boost::bind(&CWebServer::Cmd_WOLGetNodes, this, _1, _2, _3)); 403 RegisterCommandCode("woladdnode", boost::bind(&CWebServer::Cmd_WOLAddNode, this, _1, _2, _3)); 404 RegisterCommandCode("wolupdatenode", boost::bind(&CWebServer::Cmd_WOLUpdateNode, this, _1, _2, _3)); 405 RegisterCommandCode("wolremovenode", boost::bind(&CWebServer::Cmd_WOLRemoveNode, this, _1, _2, _3)); 406 RegisterCommandCode("wolclearnodes", boost::bind(&CWebServer::Cmd_WOLClearNodes, this, _1, _2, _3)); 407 408 RegisterCommandCode("mysensorsgetnodes", boost::bind(&CWebServer::Cmd_MySensorsGetNodes, this, _1, _2, _3)); 409 RegisterCommandCode("mysensorsgetchilds", boost::bind(&CWebServer::Cmd_MySensorsGetChilds, this, _1, _2, _3)); 410 RegisterCommandCode("mysensorsupdatenode", boost::bind(&CWebServer::Cmd_MySensorsUpdateNode, this, _1, _2, _3)); 411 RegisterCommandCode("mysensorsremovenode", boost::bind(&CWebServer::Cmd_MySensorsRemoveNode, this, _1, _2, _3)); 412 RegisterCommandCode("mysensorsremovechild", boost::bind(&CWebServer::Cmd_MySensorsRemoveChild, this, _1, _2, _3)); 413 RegisterCommandCode("mysensorsupdatechild", boost::bind(&CWebServer::Cmd_MySensorsUpdateChild, this, _1, _2, _3)); 414 415 RegisterCommandCode("pingersetmode", boost::bind(&CWebServer::Cmd_PingerSetMode, this, _1, _2, _3)); 416 RegisterCommandCode("pingergetnodes", boost::bind(&CWebServer::Cmd_PingerGetNodes, this, _1, _2, _3)); 417 RegisterCommandCode("pingeraddnode", boost::bind(&CWebServer::Cmd_PingerAddNode, this, _1, _2, _3)); 418 RegisterCommandCode("pingerupdatenode", boost::bind(&CWebServer::Cmd_PingerUpdateNode, this, _1, _2, _3)); 419 RegisterCommandCode("pingerremovenode", boost::bind(&CWebServer::Cmd_PingerRemoveNode, this, _1, _2, _3)); 420 RegisterCommandCode("pingerclearnodes", boost::bind(&CWebServer::Cmd_PingerClearNodes, this, _1, _2, _3)); 421 422 RegisterCommandCode("kodisetmode", boost::bind(&CWebServer::Cmd_KodiSetMode, this, _1, _2, _3)); 423 RegisterCommandCode("kodigetnodes", boost::bind(&CWebServer::Cmd_KodiGetNodes, this, _1, _2, _3)); 424 RegisterCommandCode("kodiaddnode", boost::bind(&CWebServer::Cmd_KodiAddNode, this, _1, _2, _3)); 425 RegisterCommandCode("kodiupdatenode", boost::bind(&CWebServer::Cmd_KodiUpdateNode, this, _1, _2, _3)); 426 RegisterCommandCode("kodiremovenode", boost::bind(&CWebServer::Cmd_KodiRemoveNode, this, _1, _2, _3)); 427 RegisterCommandCode("kodiclearnodes", boost::bind(&CWebServer::Cmd_KodiClearNodes, this, _1, _2, _3)); 428 RegisterCommandCode("kodimediacommand", boost::bind(&CWebServer::Cmd_KodiMediaCommand, this, _1, _2, _3)); 429 430 RegisterCommandCode("panasonicsetmode", boost::bind(&CWebServer::Cmd_PanasonicSetMode, this, _1, _2, _3)); 431 RegisterCommandCode("panasonicgetnodes", boost::bind(&CWebServer::Cmd_PanasonicGetNodes, this, _1, _2, _3)); 432 RegisterCommandCode("panasonicaddnode", boost::bind(&CWebServer::Cmd_PanasonicAddNode, this, _1, _2, _3)); 433 RegisterCommandCode("panasonicupdatenode", boost::bind(&CWebServer::Cmd_PanasonicUpdateNode, this, _1, _2, _3)); 434 RegisterCommandCode("panasonicremovenode", boost::bind(&CWebServer::Cmd_PanasonicRemoveNode, this, _1, _2, _3)); 435 RegisterCommandCode("panasonicclearnodes", boost::bind(&CWebServer::Cmd_PanasonicClearNodes, this, _1, _2, _3)); 436 RegisterCommandCode("panasonicmediacommand", boost::bind(&CWebServer::Cmd_PanasonicMediaCommand, this, _1, _2, _3)); 437 438 RegisterCommandCode("heossetmode", boost::bind(&CWebServer::Cmd_HEOSSetMode, this, _1, _2, _3)); 439 RegisterCommandCode("heosmediacommand", boost::bind(&CWebServer::Cmd_HEOSMediaCommand, this, _1, _2, _3)); 440 441 RegisterCommandCode("onkyoeiscpcommand", boost::bind(&CWebServer::Cmd_OnkyoEiscpCommand, this, _1, _2, _3)); 442 443 RegisterCommandCode("bleboxsetmode", boost::bind(&CWebServer::Cmd_BleBoxSetMode, this, _1, _2, _3)); 444 RegisterCommandCode("bleboxgetnodes", boost::bind(&CWebServer::Cmd_BleBoxGetNodes, this, _1, _2, _3)); 445 RegisterCommandCode("bleboxaddnode", boost::bind(&CWebServer::Cmd_BleBoxAddNode, this, _1, _2, _3)); 446 RegisterCommandCode("bleboxremovenode", boost::bind(&CWebServer::Cmd_BleBoxRemoveNode, this, _1, _2, _3)); 447 RegisterCommandCode("bleboxclearnodes", boost::bind(&CWebServer::Cmd_BleBoxClearNodes, this, _1, _2, _3)); 448 RegisterCommandCode("bleboxautosearchingnodes", boost::bind(&CWebServer::Cmd_BleBoxAutoSearchingNodes, this, _1, _2, _3)); 449 RegisterCommandCode("bleboxupdatefirmware", boost::bind(&CWebServer::Cmd_BleBoxUpdateFirmware, this, _1, _2, _3)); 450 451 RegisterCommandCode("lmssetmode", boost::bind(&CWebServer::Cmd_LMSSetMode, this, _1, _2, _3)); 452 RegisterCommandCode("lmsgetnodes", boost::bind(&CWebServer::Cmd_LMSGetNodes, this, _1, _2, _3)); 453 RegisterCommandCode("lmsgetplaylists", boost::bind(&CWebServer::Cmd_LMSGetPlaylists, this, _1, _2, _3)); 454 RegisterCommandCode("lmsmediacommand", boost::bind(&CWebServer::Cmd_LMSMediaCommand, this, _1, _2, _3)); 455 RegisterCommandCode("lmsdeleteunuseddevices", boost::bind(&CWebServer::Cmd_LMSDeleteUnusedDevices, this, _1, _2, _3)); 456 457 RegisterCommandCode("savefibarolinkconfig", boost::bind(&CWebServer::Cmd_SaveFibaroLinkConfig, this, _1, _2, _3)); 458 RegisterCommandCode("getfibarolinkconfig", boost::bind(&CWebServer::Cmd_GetFibaroLinkConfig, this, _1, _2, _3)); 459 RegisterCommandCode("getfibarolinks", boost::bind(&CWebServer::Cmd_GetFibaroLinks, this, _1, _2, _3)); 460 RegisterCommandCode("savefibarolink", boost::bind(&CWebServer::Cmd_SaveFibaroLink, this, _1, _2, _3)); 461 RegisterCommandCode("deletefibarolink", boost::bind(&CWebServer::Cmd_DeleteFibaroLink, this, _1, _2, _3)); 462 463 RegisterCommandCode("saveinfluxlinkconfig", boost::bind(&CWebServer::Cmd_SaveInfluxLinkConfig, this, _1, _2, _3)); 464 RegisterCommandCode("getinfluxlinkconfig", boost::bind(&CWebServer::Cmd_GetInfluxLinkConfig, this, _1, _2, _3)); 465 RegisterCommandCode("getinfluxlinks", boost::bind(&CWebServer::Cmd_GetInfluxLinks, this, _1, _2, _3)); 466 RegisterCommandCode("saveinfluxlink", boost::bind(&CWebServer::Cmd_SaveInfluxLink, this, _1, _2, _3)); 467 RegisterCommandCode("deleteinfluxlink", boost::bind(&CWebServer::Cmd_DeleteInfluxLink, this, _1, _2, _3)); 468 469 RegisterCommandCode("savehttplinkconfig", boost::bind(&CWebServer::Cmd_SaveHttpLinkConfig, this, _1, _2, _3)); 470 RegisterCommandCode("gethttplinkconfig", boost::bind(&CWebServer::Cmd_GetHttpLinkConfig, this, _1, _2, _3)); 471 RegisterCommandCode("gethttplinks", boost::bind(&CWebServer::Cmd_GetHttpLinks, this, _1, _2, _3)); 472 RegisterCommandCode("savehttplink", boost::bind(&CWebServer::Cmd_SaveHttpLink, this, _1, _2, _3)); 473 RegisterCommandCode("deletehttplink", boost::bind(&CWebServer::Cmd_DeleteHttpLink, this, _1, _2, _3)); 474 475 RegisterCommandCode("savegooglepubsublinkconfig", boost::bind(&CWebServer::Cmd_SaveGooglePubSubLinkConfig, this, _1, _2, _3)); 476 RegisterCommandCode("getgooglepubsublinkconfig", boost::bind(&CWebServer::Cmd_GetGooglePubSubLinkConfig, this, _1, _2, _3)); 477 RegisterCommandCode("getgooglepubsublinks", boost::bind(&CWebServer::Cmd_GetGooglePubSubLinks, this, _1, _2, _3)); 478 RegisterCommandCode("savegooglepubsublink", boost::bind(&CWebServer::Cmd_SaveGooglePubSubLink, this, _1, _2, _3)); 479 RegisterCommandCode("deletegooglepubsublink", boost::bind(&CWebServer::Cmd_DeleteGooglePubSubLink, this, _1, _2, _3)); 480 481 RegisterCommandCode("getdevicevalueoptions", boost::bind(&CWebServer::Cmd_GetDeviceValueOptions, this, _1, _2, _3)); 482 RegisterCommandCode("getdevicevalueoptionwording", boost::bind(&CWebServer::Cmd_GetDeviceValueOptionWording, this, _1, _2, _3)); 483 484 RegisterCommandCode("adduservariable", boost::bind(&CWebServer::Cmd_AddUserVariable, this, _1, _2, _3)); 485 RegisterCommandCode("updateuservariable", boost::bind(&CWebServer::Cmd_UpdateUserVariable, this, _1, _2, _3)); 486 RegisterCommandCode("deleteuservariable", boost::bind(&CWebServer::Cmd_DeleteUserVariable, this, _1, _2, _3)); 487 RegisterCommandCode("getuservariables", boost::bind(&CWebServer::Cmd_GetUserVariables, this, _1, _2, _3)); 488 RegisterCommandCode("getuservariable", boost::bind(&CWebServer::Cmd_GetUserVariable, this, _1, _2, _3)); 489 490 RegisterCommandCode("allownewhardware", boost::bind(&CWebServer::Cmd_AllowNewHardware, this, _1, _2, _3)); 491 492 RegisterCommandCode("addplan", boost::bind(&CWebServer::Cmd_AddPlan, this, _1, _2, _3)); 493 RegisterCommandCode("updateplan", boost::bind(&CWebServer::Cmd_UpdatePlan, this, _1, _2, _3)); 494 RegisterCommandCode("deleteplan", boost::bind(&CWebServer::Cmd_DeletePlan, this, _1, _2, _3)); 495 RegisterCommandCode("getunusedplandevices", boost::bind(&CWebServer::Cmd_GetUnusedPlanDevices, this, _1, _2, _3)); 496 RegisterCommandCode("addplanactivedevice", boost::bind(&CWebServer::Cmd_AddPlanActiveDevice, this, _1, _2, _3)); 497 RegisterCommandCode("getplandevices", boost::bind(&CWebServer::Cmd_GetPlanDevices, this, _1, _2, _3)); 498 RegisterCommandCode("deleteplandevice", boost::bind(&CWebServer::Cmd_DeletePlanDevice, this, _1, _2, _3)); 499 RegisterCommandCode("setplandevicecoords", boost::bind(&CWebServer::Cmd_SetPlanDeviceCoords, this, _1, _2, _3)); 500 RegisterCommandCode("deleteallplandevices", boost::bind(&CWebServer::Cmd_DeleteAllPlanDevices, this, _1, _2, _3)); 501 RegisterCommandCode("changeplanorder", boost::bind(&CWebServer::Cmd_ChangePlanOrder, this, _1, _2, _3)); 502 RegisterCommandCode("changeplandeviceorder", boost::bind(&CWebServer::Cmd_ChangePlanDeviceOrder, this, _1, _2, _3)); 503 504 RegisterCommandCode("gettimerplans", boost::bind(&CWebServer::Cmd_GetTimerPlans, this, _1, _2, _3)); 505 RegisterCommandCode("addtimerplan", boost::bind(&CWebServer::Cmd_AddTimerPlan, this, _1, _2, _3)); 506 RegisterCommandCode("updatetimerplan", boost::bind(&CWebServer::Cmd_UpdateTimerPlan, this, _1, _2, _3)); 507 RegisterCommandCode("deletetimerplan", boost::bind(&CWebServer::Cmd_DeleteTimerPlan, this, _1, _2, _3)); 508 RegisterCommandCode("duplicatetimerplan", boost::bind(&CWebServer::Cmd_DuplicateTimerPlan, this, _1, _2, _3)); 509 510 RegisterCommandCode("getactualhistory", boost::bind(&CWebServer::Cmd_GetActualHistory, this, _1, _2, _3)); 511 RegisterCommandCode("getnewhistory", boost::bind(&CWebServer::Cmd_GetNewHistory, this, _1, _2, _3)); 512 513 RegisterCommandCode("getconfig", boost::bind(&CWebServer::Cmd_GetConfig, this, _1, _2, _3), true); 514 RegisterCommandCode("getlocation", boost::bind(&CWebServer::Cmd_GetLocation, this, _1, _2, _3)); 515 RegisterCommandCode("sendnotification", boost::bind(&CWebServer::Cmd_SendNotification, this, _1, _2, _3)); 516 RegisterCommandCode("emailcamerasnapshot", boost::bind(&CWebServer::Cmd_EmailCameraSnapshot, this, _1, _2, _3)); 517 RegisterCommandCode("udevice", boost::bind(&CWebServer::Cmd_UpdateDevice, this, _1, _2, _3)); 518 RegisterCommandCode("udevices", boost::bind(&CWebServer::Cmd_UpdateDevices, this, _1, _2, _3)); 519 RegisterCommandCode("thermostatstate", boost::bind(&CWebServer::Cmd_SetThermostatState, this, _1, _2, _3)); 520 RegisterCommandCode("system_shutdown", boost::bind(&CWebServer::Cmd_SystemShutdown, this, _1, _2, _3)); 521 RegisterCommandCode("system_reboot", boost::bind(&CWebServer::Cmd_SystemReboot, this, _1, _2, _3)); 522 RegisterCommandCode("execute_script", boost::bind(&CWebServer::Cmd_ExcecuteScript, this, _1, _2, _3)); 523 RegisterCommandCode("getcosts", boost::bind(&CWebServer::Cmd_GetCosts, this, _1, _2, _3)); 524 RegisterCommandCode("checkforupdate", boost::bind(&CWebServer::Cmd_CheckForUpdate, this, _1, _2, _3)); 525 RegisterCommandCode("downloadupdate", boost::bind(&CWebServer::Cmd_DownloadUpdate, this, _1, _2, _3)); 526 RegisterCommandCode("downloadready", boost::bind(&CWebServer::Cmd_DownloadReady, this, _1, _2, _3)); 527 RegisterCommandCode("update_application", boost::bind(&CWebServer::Cmd_UpdateApplication, this, _1, _2, _3)); 528 RegisterCommandCode("deletedatapoint", boost::bind(&CWebServer::Cmd_DeleteDatePoint, this, _1, _2, _3)); 529 RegisterCommandCode("customevent", boost::bind(&CWebServer::Cmd_CustomEvent, this, _1, _2, _3)); 530 531 RegisterCommandCode("setactivetimerplan", boost::bind(&CWebServer::Cmd_SetActiveTimerPlan, this, _1, _2, _3)); 532 RegisterCommandCode("addtimer", boost::bind(&CWebServer::Cmd_AddTimer, this, _1, _2, _3)); 533 RegisterCommandCode("updatetimer", boost::bind(&CWebServer::Cmd_UpdateTimer, this, _1, _2, _3)); 534 RegisterCommandCode("deletetimer", boost::bind(&CWebServer::Cmd_DeleteTimer, this, _1, _2, _3)); 535 RegisterCommandCode("enabletimer", boost::bind(&CWebServer::Cmd_EnableTimer, this, _1, _2, _3)); 536 RegisterCommandCode("disabletimer", boost::bind(&CWebServer::Cmd_DisableTimer, this, _1, _2, _3)); 537 RegisterCommandCode("cleartimers", boost::bind(&CWebServer::Cmd_ClearTimers, this, _1, _2, _3)); 538 539 RegisterCommandCode("addscenetimer", boost::bind(&CWebServer::Cmd_AddSceneTimer, this, _1, _2, _3)); 540 RegisterCommandCode("updatescenetimer", boost::bind(&CWebServer::Cmd_UpdateSceneTimer, this, _1, _2, _3)); 541 RegisterCommandCode("deletescenetimer", boost::bind(&CWebServer::Cmd_DeleteSceneTimer, this, _1, _2, _3)); 542 RegisterCommandCode("enablescenetimer", boost::bind(&CWebServer::Cmd_EnableSceneTimer, this, _1, _2, _3)); 543 RegisterCommandCode("disablescenetimer", boost::bind(&CWebServer::Cmd_DisableSceneTimer, this, _1, _2, _3)); 544 RegisterCommandCode("clearscenetimers", boost::bind(&CWebServer::Cmd_ClearSceneTimers, this, _1, _2, _3)); 545 RegisterCommandCode("getsceneactivations", boost::bind(&CWebServer::Cmd_GetSceneActivations, this, _1, _2, _3)); 546 RegisterCommandCode("addscenecode", boost::bind(&CWebServer::Cmd_AddSceneCode, this, _1, _2, _3)); 547 RegisterCommandCode("removescenecode", boost::bind(&CWebServer::Cmd_RemoveSceneCode, this, _1, _2, _3)); 548 RegisterCommandCode("clearscenecodes", boost::bind(&CWebServer::Cmd_ClearSceneCodes, this, _1, _2, _3)); 549 RegisterCommandCode("renamescene", boost::bind(&CWebServer::Cmd_RenameScene, this, _1, _2, _3)); 550 551 RegisterCommandCode("setsetpoint", boost::bind(&CWebServer::Cmd_SetSetpoint, this, _1, _2, _3)); 552 RegisterCommandCode("addsetpointtimer", boost::bind(&CWebServer::Cmd_AddSetpointTimer, this, _1, _2, _3)); 553 RegisterCommandCode("updatesetpointtimer", boost::bind(&CWebServer::Cmd_UpdateSetpointTimer, this, _1, _2, _3)); 554 RegisterCommandCode("deletesetpointtimer", boost::bind(&CWebServer::Cmd_DeleteSetpointTimer, this, _1, _2, _3)); 555 RegisterCommandCode("enablesetpointtimer", boost::bind(&CWebServer::Cmd_EnableSetpointTimer, this, _1, _2, _3)); 556 RegisterCommandCode("disablesetpointtimer", boost::bind(&CWebServer::Cmd_DisableSetpointTimer, this, _1, _2, _3)); 557 RegisterCommandCode("clearsetpointtimers", boost::bind(&CWebServer::Cmd_ClearSetpointTimers, this, _1, _2, _3)); 558 559 RegisterCommandCode("serial_devices", boost::bind(&CWebServer::Cmd_GetSerialDevices, this, _1, _2, _3)); 560 RegisterCommandCode("devices_list", boost::bind(&CWebServer::Cmd_GetDevicesList, this, _1, _2, _3)); 561 RegisterCommandCode("devices_list_onoff", boost::bind(&CWebServer::Cmd_GetDevicesListOnOff, this, _1, _2, _3)); 562 563 RegisterCommandCode("registerhue", boost::bind(&CWebServer::Cmd_PhilipsHueRegister, this, _1, _2, _3)); 564 565 RegisterCommandCode("getcustomiconset", boost::bind(&CWebServer::Cmd_GetCustomIconSet, this, _1, _2, _3)); 566 RegisterCommandCode("deletecustomicon", boost::bind(&CWebServer::Cmd_DeleteCustomIcon, this, _1, _2, _3)); 567 RegisterCommandCode("updatecustomicon", boost::bind(&CWebServer::Cmd_UpdateCustomIcon, this, _1, _2, _3)); 568 569 RegisterCommandCode("renamedevice", boost::bind(&CWebServer::Cmd_RenameDevice, this, _1, _2, _3)); 570 RegisterCommandCode("setunused", boost::bind(&CWebServer::Cmd_SetUnused, this, _1, _2, _3)); 571 572 RegisterCommandCode("addlogmessage", boost::bind(&CWebServer::Cmd_AddLogMessage, this, _1, _2, _3)); 573 RegisterCommandCode("clearshortlog", boost::bind(&CWebServer::Cmd_ClearShortLog, this, _1, _2, _3)); 574 RegisterCommandCode("vacuumdatabase", boost::bind(&CWebServer::Cmd_VacuumDatabase, this, _1, _2, _3)); 575 576 RegisterCommandCode("addmobiledevice", boost::bind(&CWebServer::Cmd_AddMobileDevice, this, _1, _2, _3)); 577 RegisterCommandCode("updatemobiledevice", boost::bind(&CWebServer::Cmd_UpdateMobileDevice, this, _1, _2, _3)); 578 RegisterCommandCode("deletemobiledevice", boost::bind(&CWebServer::Cmd_DeleteMobileDevice, this, _1, _2, _3)); 579 580 RegisterCommandCode("addyeelight", boost::bind(&CWebServer::Cmd_AddYeeLight, this, _1, _2, _3)); 581 582 RegisterCommandCode("addArilux", boost::bind(&CWebServer::Cmd_AddArilux, this, _1, _2, _3)); 583 584 RegisterRType("graph", boost::bind(&CWebServer::RType_HandleGraph, this, _1, _2, _3)); 585 RegisterRType("lightlog", boost::bind(&CWebServer::RType_LightLog, this, _1, _2, _3)); 586 RegisterRType("textlog", boost::bind(&CWebServer::RType_TextLog, this, _1, _2, _3)); 587 RegisterRType("scenelog", boost::bind(&CWebServer::RType_SceneLog, this, _1, _2, _3)); 588 RegisterRType("settings", boost::bind(&CWebServer::RType_Settings, this, _1, _2, _3)); 589 RegisterRType("events", boost::bind(&CWebServer::RType_Events, this, _1, _2, _3)); 590 591 RegisterRType("hardware", boost::bind(&CWebServer::RType_Hardware, this, _1, _2, _3)); 592 RegisterRType("devices", boost::bind(&CWebServer::RType_Devices, this, _1, _2, _3)); 593 RegisterRType("deletedevice", boost::bind(&CWebServer::RType_DeleteDevice, this, _1, _2, _3)); 594 RegisterRType("cameras", boost::bind(&CWebServer::RType_Cameras, this, _1, _2, _3)); 595 RegisterRType("cameras_user", boost::bind(&CWebServer::RType_CamerasUser, this, _1, _2, _3)); 596 RegisterRType("users", boost::bind(&CWebServer::RType_Users, this, _1, _2, _3)); 597 RegisterRType("mobiles", boost::bind(&CWebServer::RType_Mobiles, this, _1, _2, _3)); 598 599 RegisterRType("timers", boost::bind(&CWebServer::RType_Timers, this, _1, _2, _3)); 600 RegisterRType("scenetimers", boost::bind(&CWebServer::RType_SceneTimers, this, _1, _2, _3)); 601 RegisterRType("setpointtimers", boost::bind(&CWebServer::RType_SetpointTimers, this, _1, _2, _3)); 602 603 RegisterRType("gettransfers", boost::bind(&CWebServer::RType_GetTransfers, this, _1, _2, _3)); 604 RegisterRType("transferdevice", boost::bind(&CWebServer::RType_TransferDevice, this, _1, _2, _3)); 605 RegisterRType("notifications", boost::bind(&CWebServer::RType_Notifications, this, _1, _2, _3)); 606 RegisterRType("schedules", boost::bind(&CWebServer::RType_Schedules, this, _1, _2, _3)); 607 RegisterRType("getshareduserdevices", boost::bind(&CWebServer::RType_GetSharedUserDevices, this, _1, _2, _3)); 608 RegisterRType("setshareduserdevices", boost::bind(&CWebServer::RType_SetSharedUserDevices, this, _1, _2, _3)); 609 RegisterRType("setused", boost::bind(&CWebServer::RType_SetUsed, this, _1, _2, _3)); 610 RegisterRType("scenes", boost::bind(&CWebServer::RType_Scenes, this, _1, _2, _3)); 611 RegisterRType("addscene", boost::bind(&CWebServer::RType_AddScene, this, _1, _2, _3)); 612 RegisterRType("deletescene", boost::bind(&CWebServer::RType_DeleteScene, this, _1, _2, _3)); 613 RegisterRType("updatescene", boost::bind(&CWebServer::RType_UpdateScene, this, _1, _2, _3)); 614 RegisterRType("createvirtualsensor", boost::bind(&CWebServer::RType_CreateMappedSensor, this, _1, _2, _3)); 615 RegisterRType("createdevice", boost::bind(&CWebServer::RType_CreateDevice, this, _1, _2, _3)); 616 617 RegisterRType("createevohomesensor", boost::bind(&CWebServer::RType_CreateEvohomeSensor, this, _1, _2, _3)); 618 RegisterRType("bindevohome", boost::bind(&CWebServer::RType_BindEvohome, this, _1, _2, _3)); 619 RegisterRType("createrflinkdevice", boost::bind(&CWebServer::RType_CreateRFLinkDevice, this, _1, _2, _3)); 620 621 RegisterRType("custom_light_icons", boost::bind(&CWebServer::RType_CustomLightIcons, this, _1, _2, _3)); 622 RegisterRType("plans", boost::bind(&CWebServer::RType_Plans, this, _1, _2, _3)); 623 RegisterRType("floorplans", boost::bind(&CWebServer::RType_FloorPlans, this, _1, _2, _3)); 624 #ifdef WITH_OPENZWAVE 625 //ZWave 626 RegisterCommandCode("updatezwavenode", boost::bind(&CWebServer::Cmd_ZWaveUpdateNode, this, _1, _2, _3)); 627 RegisterCommandCode("deletezwavenode", boost::bind(&CWebServer::Cmd_ZWaveDeleteNode, this, _1, _2, _3)); 628 RegisterCommandCode("zwaveinclude", boost::bind(&CWebServer::Cmd_ZWaveInclude, this, _1, _2, _3)); 629 RegisterCommandCode("zwaveexclude", boost::bind(&CWebServer::Cmd_ZWaveExclude, this, _1, _2, _3)); 630 631 RegisterCommandCode("zwaveisnodeincluded", boost::bind(&CWebServer::Cmd_ZWaveIsNodeIncluded, this, _1, _2, _3)); 632 RegisterCommandCode("zwaveisnodeexcluded", boost::bind(&CWebServer::Cmd_ZWaveIsNodeExcluded, this, _1, _2, _3)); 633 634 RegisterCommandCode("zwavesoftreset", boost::bind(&CWebServer::Cmd_ZWaveSoftReset, this, _1, _2, _3)); 635 RegisterCommandCode("zwavehardreset", boost::bind(&CWebServer::Cmd_ZWaveHardReset, this, _1, _2, _3)); 636 RegisterCommandCode("zwavenetworkheal", boost::bind(&CWebServer::Cmd_ZWaveNetworkHeal, this, _1, _2, _3)); 637 RegisterCommandCode("zwavenodeheal", boost::bind(&CWebServer::Cmd_ZWaveNodeHeal, this, _1, _2, _3)); 638 RegisterCommandCode("zwavenetworkinfo", boost::bind(&CWebServer::Cmd_ZWaveNetworkInfo, this, _1, _2, _3)); 639 RegisterCommandCode("zwaveremovegroupnode", boost::bind(&CWebServer::Cmd_ZWaveRemoveGroupNode, this, _1, _2, _3)); 640 RegisterCommandCode("zwaveaddgroupnode", boost::bind(&CWebServer::Cmd_ZWaveAddGroupNode, this, _1, _2, _3)); 641 RegisterCommandCode("zwavegroupinfo", boost::bind(&CWebServer::Cmd_ZWaveGroupInfo, this, _1, _2, _3)); 642 RegisterCommandCode("zwavecancel", boost::bind(&CWebServer::Cmd_ZWaveCancel, this, _1, _2, _3)); 643 RegisterCommandCode("applyzwavenodeconfig", boost::bind(&CWebServer::Cmd_ApplyZWaveNodeConfig, this, _1, _2, _3)); 644 RegisterCommandCode("requestzwavenodeconfig", boost::bind(&CWebServer::Cmd_ZWaveRequestNodeConfig, this, _1, _2, _3)); 645 RegisterCommandCode("requestzwavenodeinfo", boost::bind(&CWebServer::Cmd_ZWaveRequestNodeInfo, this, _1, _2, _3)); 646 RegisterCommandCode("zwavestatecheck", boost::bind(&CWebServer::Cmd_ZWaveStateCheck, this, _1, _2, _3)); 647 RegisterCommandCode("zwavereceiveconfigurationfromothercontroller", boost::bind(&CWebServer::Cmd_ZWaveReceiveConfigurationFromOtherController, this, _1, _2, _3)); 648 RegisterCommandCode("zwavesendconfigurationtosecondcontroller", boost::bind(&CWebServer::Cmd_ZWaveSendConfigurationToSecondaryController, this, _1, _2, _3)); 649 RegisterCommandCode("zwavetransferprimaryrole", boost::bind(&CWebServer::Cmd_ZWaveTransferPrimaryRole, this, _1, _2, _3)); 650 RegisterCommandCode("zwavestartusercodeenrollmentmode", boost::bind(&CWebServer::Cmd_ZWaveSetUserCodeEnrollmentMode, this, _1, _2, _3)); 651 RegisterCommandCode("zwavegetusercodes", boost::bind(&CWebServer::Cmd_ZWaveGetNodeUserCodes, this, _1, _2, _3)); 652 RegisterCommandCode("zwaveremoveusercode", boost::bind(&CWebServer::Cmd_ZWaveRemoveUserCode, this, _1, _2, _3)); 653 RegisterCommandCode("zwavegetbatterylevels", boost::bind(&CWebServer::Cmd_ZWaveGetBatteryLevels, this, _1, _2, _3)); 654 655 m_pWebEm->RegisterPageCode("/zwavegetconfig.php", boost::bind(&CWebServer::ZWaveGetConfigFile, this, _1, _2, _3)); 656 657 m_pWebEm->RegisterPageCode("/ozwcp/poll.xml", boost::bind(&CWebServer::ZWaveCPPollXml, this, _1, _2, _3)); 658 m_pWebEm->RegisterPageCode("/ozwcp/cp.html", boost::bind(&CWebServer::ZWaveCPIndex, this, _1, _2, _3)); 659 m_pWebEm->RegisterPageCode("/ozwcp/confparmpost.html", boost::bind(&CWebServer::ZWaveCPNodeGetConf, this, _1, _2, _3)); 660 m_pWebEm->RegisterPageCode("/ozwcp/refreshpost.html", boost::bind(&CWebServer::ZWaveCPNodeGetValues, this, _1, _2, _3)); 661 m_pWebEm->RegisterPageCode("/ozwcp/valuepost.html", boost::bind(&CWebServer::ZWaveCPNodeSetValue, this, _1, _2, _3)); 662 m_pWebEm->RegisterPageCode("/ozwcp/buttonpost.html", boost::bind(&CWebServer::ZWaveCPNodeSetButton, this, _1, _2, _3)); 663 m_pWebEm->RegisterPageCode("/ozwcp/admpost.html", boost::bind(&CWebServer::ZWaveCPAdminCommand, this, _1, _2, _3)); 664 m_pWebEm->RegisterPageCode("/ozwcp/nodepost.html", boost::bind(&CWebServer::ZWaveCPNodeChange, this, _1, _2, _3)); 665 m_pWebEm->RegisterPageCode("/ozwcp/thpost.html", boost::bind(&CWebServer::ZWaveCPTestHeal, this, _1, _2, _3)); 666 m_pWebEm->RegisterPageCode("/ozwcp/topopost.html", boost::bind(&CWebServer::ZWaveCPGetTopo, this, _1, _2, _3)); 667 m_pWebEm->RegisterPageCode("/ozwcp/statpost.html", boost::bind(&CWebServer::ZWaveCPGetStats, this, _1, _2, _3)); 668 m_pWebEm->RegisterPageCode("/ozwcp/grouppost.html", boost::bind(&CWebServer::ZWaveCPSetGroup, this, _1, _2, _3)); 669 // 670 //pollpost.html 671 RegisterRType("openzwavenodes", boost::bind(&CWebServer::RType_OpenZWaveNodes, this, _1, _2, _3)); 672 #endif 673 RegisterCommandCode("tellstickApplySettings", boost::bind(&CWebServer::Cmd_TellstickApplySettings, this, _1, _2, _3)); 674 675 m_pWebEm->RegisterWhitelistURLString("/html5.appcache"); 676 m_pWebEm->RegisterWhitelistURLString("/images/floorplans/plan"); 677 678 //Start normal worker thread 679 m_bDoStop = false; 680 m_thread = std::make_shared<std::thread>(&CWebServer::Do_Work, this); 681 std::string server_name = "WebServer_" + settings.listening_port; 682 SetThreadName(m_thread->native_handle(), server_name.c_str()); 683 return (m_thread != nullptr); 684 } 685 StopServer()686 void CWebServer::StopServer() 687 { 688 m_bDoStop = true; 689 try 690 { 691 if (m_pWebEm == NULL) 692 return; 693 m_pWebEm->Stop(); 694 if (m_thread) { 695 m_thread->join(); 696 m_thread.reset(); 697 } 698 delete m_pWebEm; 699 m_pWebEm = NULL; 700 } 701 catch (...) 702 { 703 704 } 705 } 706 SetWebCompressionMode(const _eWebCompressionMode gzmode)707 void CWebServer::SetWebCompressionMode(const _eWebCompressionMode gzmode) 708 { 709 if (m_pWebEm == NULL) 710 return; 711 m_pWebEm->SetWebCompressionMode(gzmode); 712 } 713 SetAuthenticationMethod(const _eAuthenticationMethod amethod)714 void CWebServer::SetAuthenticationMethod(const _eAuthenticationMethod amethod) 715 { 716 if (m_pWebEm == NULL) 717 return; 718 m_pWebEm->SetAuthenticationMethod(amethod); 719 } 720 SetWebTheme(const std::string & themename)721 void CWebServer::SetWebTheme(const std::string &themename) 722 { 723 if (m_pWebEm == NULL) 724 return; 725 m_pWebEm->SetWebTheme(themename); 726 } 727 SetWebRoot(const std::string & webRoot)728 void CWebServer::SetWebRoot(const std::string &webRoot) 729 { 730 if (m_pWebEm == NULL) 731 return; 732 m_pWebEm->SetWebRoot(webRoot); 733 } 734 RegisterCommandCode(const char * idname,webserver_response_function ResponseFunction,bool bypassAuthentication)735 void CWebServer::RegisterCommandCode(const char* idname, webserver_response_function ResponseFunction, bool bypassAuthentication) 736 { 737 m_webcommands.insert(std::pair<std::string, webserver_response_function >(std::string(idname), ResponseFunction)); 738 if (bypassAuthentication) 739 { 740 m_pWebEm->RegisterWhitelistCommandsString(idname); 741 } 742 } 743 RegisterRType(const char * idname,webserver_response_function ResponseFunction)744 void CWebServer::RegisterRType(const char* idname, webserver_response_function ResponseFunction) 745 { 746 m_webrtypes.insert(std::pair<std::string, webserver_response_function >(std::string(idname), ResponseFunction)); 747 } 748 HandleRType(const std::string & rtype,WebEmSession & session,const request & req,Json::Value & root)749 void CWebServer::HandleRType(const std::string &rtype, WebEmSession & session, const request& req, Json::Value &root) 750 { 751 std::map < std::string, webserver_response_function >::iterator pf = m_webrtypes.find(rtype); 752 if (pf != m_webrtypes.end()) 753 { 754 pf->second(session, req, root); 755 } 756 } 757 GetAppCache(WebEmSession & session,const request & req,reply & rep)758 void CWebServer::GetAppCache(WebEmSession & session, const request& req, reply & rep) 759 { 760 std::string response = ""; 761 if (g_bDontCacheWWW) 762 { 763 return; 764 } 765 //Return the appcache file (dynamically generated) 766 std::string sLine; 767 std::string filename = szWWWFolder + "/html5.appcache"; 768 769 770 std::string sWebTheme = "default"; 771 m_sql.GetPreferencesVar("WebTheme", sWebTheme); 772 773 //Get Dynamic Theme Files 774 std::map<std::string, int> _ThemeFiles; 775 GetDirFilesRecursive(szWWWFolder + "/styles/" + sWebTheme + "/", _ThemeFiles); 776 777 //Get Dynamic Floorplan Images from database 778 std::map<std::string, int> _FloorplanFiles; 779 std::vector<std::vector<std::string> > result; 780 result = m_sql.safe_query("SELECT ID FROM Floorplans ORDER BY [Order]"); 781 if (!result.empty()) 782 { 783 for (const auto & itt : result) 784 { 785 std::vector<std::string> sd = itt; 786 std::string ImageURL = "images/floorplans/plan?idx=" + sd[0]; 787 _FloorplanFiles[ImageURL] = 1; 788 } 789 } 790 791 std::ifstream is(filename.c_str()); 792 if (is) 793 { 794 while (!is.eof()) 795 { 796 getline(is, sLine); 797 if (!sLine.empty()) 798 { 799 if (sLine.find("#BuildHash") != std::string::npos) 800 { 801 stdreplace(sLine, "#BuildHash", szAppHash); 802 } 803 else if (sLine.find("#ThemeFiles") != std::string::npos) 804 { 805 response += "#Theme=" + sWebTheme + '\n'; 806 //Add all theme files 807 for (const auto & itt : _ThemeFiles) 808 { 809 std::string tfname = itt.first.substr(szWWWFolder.size() + 1); 810 stdreplace(tfname, "styles/" + sWebTheme, "acttheme"); 811 response += tfname + '\n'; 812 } 813 continue; 814 } 815 else if (sLine.find("#Floorplans") != std::string::npos) 816 { 817 //Add all floorplans 818 for (const auto & itt : _FloorplanFiles) 819 { 820 std::string tfname = itt.first; 821 response += tfname + '\n'; 822 } 823 continue; 824 } 825 else if (sLine.find("#SwitchIcons") != std::string::npos) 826 { 827 //Add database switch icons 828 for (const auto & itt : m_custom_light_icons) 829 { 830 if (itt.idx >= 100) 831 { 832 std::string IconFile16 = itt.RootFile + ".png"; 833 std::string IconFile48On = itt.RootFile + "48_On.png"; 834 std::string IconFile48Off = itt.RootFile + "48_Off.png"; 835 836 response += "images/" + CURLEncode::URLEncode(IconFile16) + '\n'; 837 response += "images/" + CURLEncode::URLEncode(IconFile48On) + '\n'; 838 response += "images/" + CURLEncode::URLEncode(IconFile48Off) + '\n'; 839 } 840 } 841 } 842 } 843 response += sLine + '\n'; 844 } 845 } 846 reply::set_content(&rep, response); 847 } 848 GetJSonPage(WebEmSession & session,const request & req,reply & rep)849 void CWebServer::GetJSonPage(WebEmSession & session, const request& req, reply & rep) 850 { 851 Json::Value root; 852 root["status"] = "ERR"; 853 854 std::string rtype = request::findValue(&req, "type"); 855 if (rtype == "command") 856 { 857 std::string cparam = request::findValue(&req, "param"); 858 if (cparam.empty()) 859 { 860 cparam = request::findValue(&req, "dparam"); 861 if (cparam.empty()) 862 { 863 goto exitjson; 864 } 865 } 866 if (cparam == "dologout") 867 { 868 session.forcelogin = true; 869 root["status"] = "OK"; 870 root["title"] = "Logout"; 871 goto exitjson; 872 873 } 874 _log.Debug(DEBUG_WEBSERVER, "WEBS GetJSon :%s :%s ", cparam.c_str(), req.uri.c_str()); 875 HandleCommand(cparam, session, req, root); 876 } //(rtype=="command") 877 else { 878 HandleRType(rtype, session, req, root); 879 } 880 exitjson: 881 std::string jcallback = request::findValue(&req, "jsoncallback"); 882 if (jcallback.size() == 0) { 883 reply::set_content(&rep, root.toStyledString()); 884 return; 885 } 886 reply::set_content(&rep, "var data=" + root.toStyledString() + '\n' + jcallback + "(data);"); 887 } 888 Cmd_GetLanguage(WebEmSession & session,const request & req,Json::Value & root)889 void CWebServer::Cmd_GetLanguage(WebEmSession & session, const request& req, Json::Value &root) 890 { 891 std::string sValue; 892 if (m_sql.GetPreferencesVar("Language", sValue)) 893 { 894 root["status"] = "OK"; 895 root["title"] = "GetLanguage"; 896 root["language"] = sValue; 897 } 898 } 899 Cmd_GetThemes(WebEmSession & session,const request & req,Json::Value & root)900 void CWebServer::Cmd_GetThemes(WebEmSession & session, const request& req, Json::Value &root) 901 { 902 root["status"] = "OK"; 903 root["title"] = "GetThemes"; 904 m_mainworker.GetAvailableWebThemes(); 905 int ii = 0; 906 for (const auto & itt : m_mainworker.m_webthemes) 907 { 908 root["result"][ii]["theme"] = itt; 909 ii++; 910 } 911 } 912 Cmd_GetTitle(WebEmSession & session,const request & req,Json::Value & root)913 void CWebServer::Cmd_GetTitle(WebEmSession & session, const request& req, Json::Value &root) 914 { 915 std::string sValue; 916 root["status"] = "OK"; 917 root["title"] = "GetTitle"; 918 if (m_sql.GetPreferencesVar("Title", sValue)) 919 root["Title"] = sValue; 920 else 921 root["Title"] = "Domoticz"; 922 } 923 924 //PostSettings PostLoginCheck(WebEmSession & session,const request & req,reply & rep)925 void CWebServer::PostLoginCheck(WebEmSession& session, const request& req, reply& rep) 926 { 927 Json::Value root; 928 Cmd_LoginCheck(session, req, root); 929 930 std::string jcallback = request::findValue(&req, "jsoncallback"); 931 if (jcallback.size() == 0) { 932 reply::set_content(&rep, root.toStyledString()); 933 return; 934 } 935 reply::set_content(&rep, "var data=" + root.toStyledString() + '\n' + jcallback + "(data);"); 936 } 937 Cmd_LoginCheck(WebEmSession & session,const request & req,Json::Value & root)938 void CWebServer::Cmd_LoginCheck(WebEmSession & session, const request& req, Json::Value &root) 939 { 940 std::string tmpusrname = request::findValue(&req, "username"); 941 std::string tmpusrpass = request::findValue(&req, "password"); 942 if ( 943 (tmpusrname.empty()) || 944 (tmpusrpass.empty()) 945 ) 946 return; 947 948 std::string rememberme = request::findValue(&req, "rememberme"); 949 950 std::string usrname; 951 std::string usrpass; 952 if (request_handler::url_decode(tmpusrname, usrname)) 953 { 954 if (request_handler::url_decode(tmpusrpass, usrpass)) 955 { 956 usrname = base64_decode(usrname); 957 int iUser = FindUser(usrname.c_str()); 958 if (iUser == -1) { 959 // log brute force attack 960 _log.Log(LOG_ERROR, "Failed login attempt from %s for user '%s' !", session.remote_host.c_str(), usrname.c_str()); 961 return; 962 } 963 if (m_users[iUser].Password != usrpass) { 964 // log brute force attack 965 _log.Log(LOG_ERROR, "Failed login attempt from %s for '%s' !", session.remote_host.c_str(), m_users[iUser].Username.c_str()); 966 return; 967 } 968 _log.Log(LOG_STATUS, "Login successful from %s for user '%s'", session.remote_host.c_str(), m_users[iUser].Username.c_str()); 969 root["status"] = "OK"; 970 root["version"] = szAppVersion; 971 root["title"] = "logincheck"; 972 session.isnew = true; 973 session.username = m_users[iUser].Username; 974 session.rights = m_users[iUser].userrights; 975 session.rememberme = (rememberme == "true"); 976 root["user"] = session.username; 977 root["rights"] = session.rights; 978 } 979 } 980 } 981 Cmd_GetHardwareTypes(WebEmSession & session,const request & req,Json::Value & root)982 void CWebServer::Cmd_GetHardwareTypes(WebEmSession & session, const request& req, Json::Value &root) 983 { 984 if (session.rights != 2) 985 { 986 session.reply_status = reply::forbidden; 987 return; //Only admin user allowed 988 } 989 990 root["status"] = "OK"; 991 root["title"] = "GetHardwareTypes"; 992 std::map<std::string, int> _htypes; 993 for (int ii = 0; ii < HTYPE_END; ii++) 994 { 995 bool bDoAdd = true; 996 #ifndef _DEBUG 997 #ifdef WIN32 998 if ( 999 (ii == HTYPE_RaspberryBMP085) || 1000 (ii == HTYPE_RaspberryHTU21D) || 1001 (ii == HTYPE_RaspberryTSL2561) || 1002 (ii == HTYPE_RaspberryPCF8574) || 1003 (ii == HTYPE_RaspberryBME280) || 1004 (ii == HTYPE_RaspberryMCP23017) 1005 ) 1006 { 1007 bDoAdd = false; 1008 } 1009 else 1010 { 1011 #ifndef WITH_LIBUSB 1012 if ( 1013 (ii == HTYPE_VOLCRAFTCO20) || 1014 (ii == HTYPE_TE923) 1015 ) 1016 { 1017 bDoAdd = false; 1018 } 1019 #endif 1020 1021 } 1022 #endif 1023 #endif 1024 #ifndef WITH_OPENZWAVE 1025 if (ii == HTYPE_OpenZWave) 1026 bDoAdd = false; 1027 #endif 1028 #ifndef WITH_GPIO 1029 if (ii == HTYPE_RaspberryGPIO) 1030 { 1031 bDoAdd = false; 1032 } 1033 1034 if (ii == HTYPE_SysfsGpio) 1035 { 1036 bDoAdd = false; 1037 } 1038 #endif 1039 if (ii == HTYPE_PythonPlugin) 1040 bDoAdd = false; 1041 if (bDoAdd) 1042 _htypes[Hardware_Type_Desc(ii)] = ii; 1043 } 1044 //return a sorted hardware list 1045 int ii = 0; 1046 for (const auto & itt : _htypes) 1047 { 1048 root["result"][ii]["idx"] = itt.second; 1049 root["result"][ii]["name"] = itt.first; 1050 ii++; 1051 } 1052 1053 #ifdef ENABLE_PYTHON 1054 // Append Plugin list as well 1055 PluginList(root["result"]); 1056 #endif 1057 } 1058 Cmd_AddHardware(WebEmSession & session,const request & req,Json::Value & root)1059 void CWebServer::Cmd_AddHardware(WebEmSession & session, const request& req, Json::Value &root) 1060 { 1061 if (session.rights != 2) 1062 { 1063 session.reply_status = reply::forbidden; 1064 return; //Only admin user allowed 1065 } 1066 1067 std::string name = HTMLSanitizer::Sanitize(CURLEncode::URLDecode(request::findValue(&req, "name"))); 1068 std::string senabled = request::findValue(&req, "enabled"); 1069 std::string shtype = request::findValue(&req, "htype"); 1070 std::string address = HTMLSanitizer::Sanitize(request::findValue(&req, "address")); 1071 std::string sport = request::findValue(&req, "port"); 1072 std::string username = HTMLSanitizer::Sanitize(CURLEncode::URLDecode(request::findValue(&req, "username"))); 1073 std::string password = HTMLSanitizer::Sanitize(CURLEncode::URLDecode(request::findValue(&req, "password"))); 1074 std::string extra = CURLEncode::URLDecode(request::findValue(&req, "extra")); 1075 std::string sdatatimeout = request::findValue(&req, "datatimeout"); 1076 if ( 1077 (name.empty()) || 1078 (senabled.empty()) || 1079 (shtype.empty()) 1080 ) 1081 return; 1082 _eHardwareTypes htype = (_eHardwareTypes)atoi(shtype.c_str()); 1083 1084 int iDataTimeout = atoi(sdatatimeout.c_str()); 1085 int mode1 = 0; 1086 int mode2 = 0; 1087 int mode3 = 0; 1088 int mode4 = 0; 1089 int mode5 = 0; 1090 int mode6 = 0; 1091 int port = atoi(sport.c_str()); 1092 std::string mode1Str = request::findValue(&req, "Mode1"); 1093 if (!mode1Str.empty()) { 1094 mode1 = atoi(mode1Str.c_str()); 1095 } 1096 std::string mode2Str = request::findValue(&req, "Mode2"); 1097 if (!mode2Str.empty()) { 1098 mode2 = atoi(mode2Str.c_str()); 1099 } 1100 std::string mode3Str = request::findValue(&req, "Mode3"); 1101 if (!mode3Str.empty()) { 1102 mode3 = atoi(mode3Str.c_str()); 1103 } 1104 std::string mode4Str = request::findValue(&req, "Mode4"); 1105 if (!mode4Str.empty()) { 1106 mode4 = atoi(mode4Str.c_str()); 1107 } 1108 std::string mode5Str = request::findValue(&req, "Mode5"); 1109 if (!mode5Str.empty()) { 1110 mode5 = atoi(mode5Str.c_str()); 1111 } 1112 std::string mode6Str = request::findValue(&req, "Mode6"); 1113 if (!mode6Str.empty()) { 1114 mode6 = atoi(mode6Str.c_str()); 1115 } 1116 1117 if (IsSerialDevice(htype)) 1118 { 1119 //USB/System 1120 if (sport.empty()) 1121 return; //need to have a serial port 1122 1123 if (htype == HTYPE_TeleinfoMeter) { 1124 // Teleinfo always has decimals. Chances to have a P1 and a Teleinfo device on the same 1125 // Domoticz instance are very low as both are national standards (NL and FR) 1126 m_sql.UpdatePreferencesVar("SmartMeterType", 0); 1127 } 1128 } 1129 else if (IsNetworkDevice(htype)) 1130 { 1131 //Lan 1132 if (address.empty() || port == 0) 1133 return; 1134 1135 if (htype == HTYPE_MySensorsMQTT || htype == HTYPE_MQTT) { 1136 std::string modeqStr = request::findValue(&req, "mode1"); 1137 if (!modeqStr.empty()) { 1138 mode1 = atoi(modeqStr.c_str()); 1139 } 1140 } 1141 1142 if (htype == HTYPE_ECODEVICES) { 1143 // EcoDevices always have decimals. Chances to have a P1 and a EcoDevice/Teleinfo device on the same 1144 // Domoticz instance are very low as both are national standards (NL and FR) 1145 m_sql.UpdatePreferencesVar("SmartMeterType", 0); 1146 } 1147 } 1148 else if (htype == HTYPE_DomoticzInternal) { 1149 // DomoticzInternal cannot be added manually 1150 return; 1151 } 1152 else if (htype == HTYPE_Domoticz) { 1153 //Remote Domoticz 1154 if (address.empty() || port == 0) 1155 return; 1156 } 1157 else if (htype == HTYPE_TE923) { 1158 //all fine here! 1159 } 1160 else if (htype == HTYPE_VOLCRAFTCO20) { 1161 //all fine here! 1162 } 1163 else if (htype == HTYPE_System) { 1164 //There should be only one 1165 std::vector<std::vector<std::string> > result; 1166 result = m_sql.safe_query("SELECT ID FROM Hardware WHERE (Type==%d)", HTYPE_System); 1167 if (!result.empty()) 1168 return; 1169 } 1170 else if (htype == HTYPE_1WIRE) { 1171 //all fine here! 1172 } 1173 else if (htype == HTYPE_Rtl433) { 1174 //all fine here! 1175 } 1176 else if (htype == HTYPE_Pinger) { 1177 //all fine here! 1178 } 1179 else if (htype == HTYPE_Kodi) { 1180 //all fine here! 1181 } 1182 else if (htype == HTYPE_PanasonicTV) { 1183 // all fine here! 1184 } 1185 else if (htype == HTYPE_LogitechMediaServer) { 1186 //all fine here! 1187 } 1188 else if (htype == HTYPE_RaspberryBMP085) { 1189 //all fine here! 1190 } 1191 else if (htype == HTYPE_RaspberryHTU21D) { 1192 //all fine here! 1193 } 1194 else if (htype == HTYPE_RaspberryTSL2561) { 1195 //all fine here! 1196 } 1197 else if (htype == HTYPE_RaspberryBME280) { 1198 //all fine here! 1199 } 1200 else if (htype == HTYPE_RaspberryMCP23017) { 1201 //all fine here! 1202 } 1203 else if (htype == HTYPE_Dummy) { 1204 //all fine here! 1205 } 1206 else if (htype == HTYPE_Tellstick) { 1207 //all fine here! 1208 } 1209 else if (htype == HTYPE_EVOHOME_SCRIPT || htype == HTYPE_EVOHOME_SERIAL || htype == HTYPE_EVOHOME_WEB || htype == HTYPE_EVOHOME_TCP) { 1210 //all fine here! 1211 } 1212 else if (htype == HTYPE_PiFace) { 1213 //all fine here! 1214 } 1215 else if (htype == HTYPE_HTTPPOLLER) { 1216 //all fine here! 1217 } 1218 else if (htype == HTYPE_BleBox) { 1219 //all fine here! 1220 } 1221 else if (htype == HTYPE_HEOS) { 1222 //all fine here! 1223 } 1224 else if (htype == HTYPE_Yeelight) { 1225 //all fine here! 1226 } 1227 else if (htype == HTYPE_XiaomiGateway) { 1228 //all fine here! 1229 } 1230 else if (htype == HTYPE_Arilux) { 1231 //all fine here! 1232 } 1233 else if (htype == HTYPE_USBtinGateway) { 1234 //All fine here 1235 } 1236 else if (htype == HTYPE_BuienRadar) { 1237 //All fine here 1238 } 1239 else if ( 1240 (htype == HTYPE_Wunderground) || 1241 (htype == HTYPE_DarkSky) || 1242 (htype == HTYPE_AccuWeather) || 1243 (htype == HTYPE_OpenWeatherMap) || 1244 (htype == HTYPE_ICYTHERMOSTAT) || 1245 (htype == HTYPE_TOONTHERMOSTAT) || 1246 (htype == HTYPE_AtagOne) || 1247 (htype == HTYPE_PVOUTPUT_INPUT) || 1248 (htype == HTYPE_NEST) || 1249 (htype == HTYPE_ANNATHERMOSTAT) || 1250 (htype == HTYPE_THERMOSMART) || 1251 (htype == HTYPE_Tado) || 1252 (htype == HTYPE_Tesla) || 1253 (htype == HTYPE_Netatmo) 1254 ) 1255 { 1256 if ( 1257 (username.empty()) || 1258 (password.empty()) 1259 ) 1260 return; 1261 } 1262 else if (htype == HTYPE_SolarEdgeAPI) 1263 { 1264 if ( 1265 (username.empty()) 1266 ) 1267 return; 1268 } 1269 else if (htype == HTYPE_Nest_OAuthAPI) { 1270 if ( 1271 (username == "") && 1272 (extra == "||") 1273 ) 1274 return; 1275 } 1276 else if (htype == HTYPE_SBFSpot) { 1277 if (username.empty()) 1278 return; 1279 } 1280 else if (htype == HTYPE_HARMONY_HUB) { 1281 if ( 1282 (address.empty() || port == 0) 1283 ) 1284 return; 1285 } 1286 else if (htype == HTYPE_Philips_Hue) { 1287 if ( 1288 (username.empty()) || 1289 (address.empty() || port == 0) 1290 ) 1291 return; 1292 if (port == 0) 1293 port = 80; 1294 } 1295 else if (htype == HTYPE_WINDDELEN) { 1296 std::string mill_id = request::findValue(&req, "Mode1"); 1297 if ( 1298 (mill_id.empty()) || 1299 (sport.empty()) 1300 ) 1301 1302 return; 1303 mode1 = atoi(mill_id.c_str()); 1304 } 1305 else if (htype == HTYPE_Honeywell) { 1306 //all fine here! 1307 } 1308 else if (htype == HTYPE_RaspberryGPIO) { 1309 //all fine here! 1310 } 1311 else if (htype == HTYPE_SysfsGpio) { 1312 //all fine here! 1313 } 1314 else if (htype == HTYPE_OpenWebNetTCP) { 1315 //All fine here 1316 } 1317 else if (htype == HTYPE_Daikin) { 1318 //All fine here 1319 } 1320 else if (htype == HTYPE_GoodweAPI) { 1321 if (username.empty()) 1322 return; 1323 } 1324 else if (htype == HTYPE_PythonPlugin) { 1325 //All fine here 1326 } 1327 else if (htype == HTYPE_RaspberryPCF8574) { 1328 //All fine here 1329 } 1330 else if (htype == HTYPE_OpenWebNetUSB) { 1331 //All fine here 1332 } 1333 else if (htype == HTYPE_IntergasInComfortLAN2RF) { 1334 //All fine here 1335 } 1336 else if (htype == HTYPE_EnphaseAPI) { 1337 //All fine here 1338 } 1339 else if (htype == HTYPE_EcoCompteur) { 1340 //all fine here! 1341 } 1342 else 1343 return; 1344 1345 root["status"] = "OK"; 1346 root["title"] = "AddHardware"; 1347 1348 std::vector<std::vector<std::string> > result; 1349 1350 if (htype == HTYPE_Domoticz) 1351 { 1352 if (password.size() != 32) 1353 { 1354 password = GenerateMD5Hash(password); 1355 } 1356 } 1357 else if ((htype == HTYPE_S0SmartMeterUSB) || (htype == HTYPE_S0SmartMeterTCP)) 1358 { 1359 extra = "0;1000;0;1000;0;1000;0;1000;0;1000"; 1360 } 1361 else if (htype == HTYPE_Pinger) 1362 { 1363 mode1 = 30; 1364 mode2 = 1000; 1365 } 1366 else if (htype == HTYPE_Kodi) 1367 { 1368 mode1 = 30; 1369 mode2 = 1000; 1370 } 1371 else if (htype == HTYPE_PanasonicTV) 1372 { 1373 mode1 = 30; 1374 mode2 = 1000; 1375 } 1376 else if (htype == HTYPE_LogitechMediaServer) 1377 { 1378 mode1 = 30; 1379 mode2 = 1000; 1380 } 1381 else if (htype == HTYPE_HEOS) 1382 { 1383 mode1 = 30; 1384 mode2 = 1000; 1385 } 1386 else if (htype == HTYPE_Tellstick) 1387 { 1388 mode1 = 4; 1389 mode2 = 500; 1390 } 1391 1392 if (htype == HTYPE_HTTPPOLLER) { 1393 m_sql.safe_query( 1394 "INSERT INTO Hardware (Name, Enabled, Type, Address, Port, SerialPort, Username, Password, Extra, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6, DataTimeout) VALUES ('%q',%d, %d,'%q',%d,'%q','%q','%q','%q','%q','%q', '%q', '%q', '%q', '%q', %d)", 1395 name.c_str(), 1396 (senabled == "true") ? 1 : 0, 1397 htype, 1398 address.c_str(), 1399 port, 1400 sport.c_str(), 1401 username.c_str(), 1402 password.c_str(), 1403 extra.c_str(), 1404 mode1Str.c_str(), mode2Str.c_str(), mode3Str.c_str(), mode4Str.c_str(), mode5Str.c_str(), mode6Str.c_str(), 1405 iDataTimeout 1406 ); 1407 } 1408 else if (htype == HTYPE_PythonPlugin) { 1409 sport = request::findValue(&req, "serialport"); 1410 m_sql.safe_query( 1411 "INSERT INTO Hardware (Name, Enabled, Type, Address, Port, SerialPort, Username, Password, Extra, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6, DataTimeout) VALUES ('%q',%d, %d,'%q',%d,'%q','%q','%q','%q','%q','%q', '%q', '%q', '%q', '%q', %d)", 1412 name.c_str(), 1413 (senabled == "true") ? 1 : 0, 1414 htype, 1415 address.c_str(), 1416 port, 1417 sport.c_str(), 1418 username.c_str(), 1419 password.c_str(), 1420 extra.c_str(), 1421 mode1Str.c_str(), mode2Str.c_str(), mode3Str.c_str(), mode4Str.c_str(), mode5Str.c_str(), mode6Str.c_str(), 1422 iDataTimeout 1423 ); 1424 } 1425 else if ( 1426 (htype == HTYPE_RFXtrx433)|| 1427 (htype == HTYPE_RFXtrx868) 1428 ) 1429 { 1430 //No Extra field here, handled in CWebServer::SetRFXCOMMode 1431 m_sql.safe_query( 1432 "INSERT INTO Hardware (Name, Enabled, Type, Address, Port, SerialPort, Username, Password, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6, DataTimeout) VALUES ('%q',%d, %d,'%q',%d,'%q','%q','%q',%d,%d,%d,%d,%d,%d,%d)", 1433 name.c_str(), 1434 (senabled == "true") ? 1 : 0, 1435 htype, 1436 address.c_str(), 1437 port, 1438 sport.c_str(), 1439 username.c_str(), 1440 password.c_str(), 1441 mode1, mode2, mode3, mode4, mode5, mode6, 1442 iDataTimeout 1443 ); 1444 extra = "0"; 1445 } 1446 else { 1447 m_sql.safe_query( 1448 "INSERT INTO Hardware (Name, Enabled, Type, Address, Port, SerialPort, Username, Password, Extra, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6, DataTimeout) VALUES ('%q',%d, %d,'%q',%d,'%q','%q','%q','%q',%d,%d,%d,%d,%d,%d,%d)", 1449 name.c_str(), 1450 (senabled == "true") ? 1 : 0, 1451 htype, 1452 address.c_str(), 1453 port, 1454 sport.c_str(), 1455 username.c_str(), 1456 password.c_str(), 1457 extra.c_str(), 1458 mode1, mode2, mode3, mode4, mode5, mode6, 1459 iDataTimeout 1460 ); 1461 } 1462 1463 //add the device for real in our system 1464 result = m_sql.safe_query("SELECT MAX(ID) FROM Hardware"); 1465 if (!result.empty()) 1466 { 1467 std::vector<std::string> sd = result[0]; 1468 int ID = atoi(sd[0].c_str()); 1469 1470 root["idx"] = sd[0].c_str(); // OTO output the created ID for easier management on the caller side (if automated) 1471 1472 m_mainworker.AddHardwareFromParams(ID, name, (senabled == "true") ? true : false, htype, address, port, sport, username, password, extra, mode1, mode2, mode3, mode4, mode5, mode6, iDataTimeout, true); 1473 } 1474 } 1475 Cmd_UpdateHardware(WebEmSession & session,const request & req,Json::Value & root)1476 void CWebServer::Cmd_UpdateHardware(WebEmSession & session, const request& req, Json::Value &root) 1477 { 1478 if (session.rights != 2) 1479 { 1480 session.reply_status = reply::forbidden; 1481 return; //Only admin user allowed 1482 } 1483 1484 std::string idx = request::findValue(&req, "idx"); 1485 if (idx.empty()) 1486 return; 1487 std::string name = HTMLSanitizer::Sanitize(CURLEncode::URLDecode(request::findValue(&req, "name"))); 1488 std::string senabled = request::findValue(&req, "enabled"); 1489 std::string shtype = request::findValue(&req, "htype"); 1490 std::string address = HTMLSanitizer::Sanitize(request::findValue(&req, "address")); 1491 std::string sport = request::findValue(&req, "port"); 1492 std::string username = HTMLSanitizer::Sanitize(CURLEncode::URLDecode(request::findValue(&req, "username"))); 1493 std::string password = CURLEncode::URLDecode(request::findValue(&req, "password")); 1494 std::string extra = HTMLSanitizer::Sanitize(CURLEncode::URLDecode(request::findValue(&req, "extra"))); 1495 std::string sdatatimeout = request::findValue(&req, "datatimeout"); 1496 1497 if ( 1498 (name.empty()) || 1499 (senabled.empty()) || 1500 (shtype.empty()) 1501 ) 1502 return; 1503 1504 int mode1 = atoi(request::findValue(&req, "Mode1").c_str()); 1505 int mode2 = atoi(request::findValue(&req, "Mode2").c_str()); 1506 int mode3 = atoi(request::findValue(&req, "Mode3").c_str()); 1507 int mode4 = atoi(request::findValue(&req, "Mode4").c_str()); 1508 int mode5 = atoi(request::findValue(&req, "Mode5").c_str()); 1509 int mode6 = atoi(request::findValue(&req, "Mode6").c_str()); 1510 1511 bool bEnabled = (senabled == "true") ? true : false; 1512 1513 _eHardwareTypes htype = (_eHardwareTypes)atoi(shtype.c_str()); 1514 int iDataTimeout = atoi(sdatatimeout.c_str()); 1515 1516 int port = atoi(sport.c_str()); 1517 1518 bool bIsSerial = false; 1519 1520 if (IsSerialDevice(htype)) 1521 { 1522 //USB/System 1523 bIsSerial = true; 1524 if (bEnabled) 1525 { 1526 if (sport.empty()) 1527 return; //need to have a serial port 1528 } 1529 } 1530 else if ( 1531 (htype == HTYPE_RFXLAN) || (htype == HTYPE_P1SmartMeterLAN) 1532 || (htype == HTYPE_YouLess) || (htype == HTYPE_OpenThermGatewayTCP) || (htype == HTYPE_LimitlessLights) 1533 || (htype == HTYPE_SolarEdgeTCP) || (htype == HTYPE_WOL) || (htype == HTYPE_S0SmartMeterTCP) || (htype == HTYPE_ECODEVICES) || (htype == HTYPE_Mochad) 1534 || (htype == HTYPE_MySensorsTCP) || (htype == HTYPE_MySensorsMQTT) || (htype == HTYPE_MQTT) || (htype == HTYPE_TTN_MQTT) || (htype == HTYPE_FRITZBOX) || (htype == HTYPE_ETH8020) || (htype == HTYPE_Sterbox) 1535 || (htype == HTYPE_KMTronicTCP) || (htype == HTYPE_KMTronicUDP) || (htype == HTYPE_SOLARMAXTCP) || (htype == HTYPE_RelayNet) || (htype == HTYPE_SatelIntegra) || (htype == HTYPE_eHouseTCP) || (htype == HTYPE_RFLINKTCP) 1536 || (htype == HTYPE_Comm5TCP || (htype == HTYPE_Comm5SMTCP) || (htype == HTYPE_CurrentCostMeterLAN)) 1537 || (htype == HTYPE_NefitEastLAN) || (htype == HTYPE_DenkoviHTTPDevices) || (htype == HTYPE_DenkoviTCPDevices) || (htype == HTYPE_Ec3kMeterTCP) || (htype == HTYPE_MultiFun) || (htype == HTYPE_ZIBLUETCP) || (htype == HTYPE_OnkyoAVTCP) 1538 || (htype == HTYPE_OctoPrint) 1539 ) { 1540 //Lan 1541 if (address.empty()) 1542 return; 1543 } 1544 else if (htype == HTYPE_DomoticzInternal) { 1545 // DomoticzInternal cannot be updated 1546 return; 1547 } 1548 else if (htype == HTYPE_Domoticz) { 1549 //Remote Domoticz 1550 if (address.empty()) 1551 return; 1552 } 1553 else if (htype == HTYPE_System) { 1554 //There should be only one, and with this ID 1555 std::vector<std::vector<std::string> > result; 1556 result = m_sql.safe_query("SELECT ID FROM Hardware WHERE (Type==%d)", HTYPE_System); 1557 if (!result.empty()) 1558 { 1559 int hID = atoi(result[0][0].c_str()); 1560 int aID = atoi(idx.c_str()); 1561 if (hID != aID) 1562 return; 1563 } 1564 } 1565 else if (htype == HTYPE_TE923) { 1566 //All fine here 1567 } 1568 else if (htype == HTYPE_VOLCRAFTCO20) { 1569 //All fine here 1570 } 1571 else if (htype == HTYPE_1WIRE) { 1572 //All fine here 1573 } 1574 else if (htype == HTYPE_Pinger) { 1575 //All fine here 1576 } 1577 else if (htype == HTYPE_Kodi) { 1578 //All fine here 1579 } 1580 else if (htype == HTYPE_PanasonicTV) { 1581 //All fine here 1582 } 1583 else if (htype == HTYPE_LogitechMediaServer) { 1584 //All fine here 1585 } 1586 else if (htype == HTYPE_RaspberryBMP085) { 1587 //All fine here 1588 } 1589 else if (htype == HTYPE_RaspberryHTU21D) { 1590 //All fine here 1591 } 1592 else if (htype == HTYPE_RaspberryTSL2561) { 1593 //All fine here 1594 } 1595 else if (htype == HTYPE_RaspberryBME280) { 1596 //All fine here 1597 } 1598 else if (htype == HTYPE_RaspberryMCP23017) { 1599 //all fine here! 1600 } 1601 else if (htype == HTYPE_Dummy) { 1602 //All fine here 1603 } 1604 else if (htype == HTYPE_EVOHOME_SCRIPT || htype == HTYPE_EVOHOME_SERIAL || htype == HTYPE_EVOHOME_WEB || htype == HTYPE_EVOHOME_TCP) { 1605 //All fine here 1606 } 1607 else if (htype == HTYPE_PiFace) { 1608 //All fine here 1609 } 1610 else if (htype == HTYPE_HTTPPOLLER) { 1611 //all fine here! 1612 } 1613 else if (htype == HTYPE_BleBox) { 1614 //All fine here 1615 } 1616 else if (htype == HTYPE_HEOS) { 1617 //All fine here 1618 } 1619 else if (htype == HTYPE_Yeelight) { 1620 //All fine here 1621 } 1622 else if (htype == HTYPE_XiaomiGateway) { 1623 //All fine here 1624 } 1625 else if (htype == HTYPE_Arilux) { 1626 //All fine here 1627 } 1628 else if (htype == HTYPE_USBtinGateway) { 1629 //All fine here 1630 } 1631 else if (htype == HTYPE_BuienRadar) { 1632 //All fine here 1633 } 1634 else if ( 1635 (htype == HTYPE_Wunderground) || 1636 (htype == HTYPE_DarkSky) || 1637 (htype == HTYPE_AccuWeather) || 1638 (htype == HTYPE_OpenWeatherMap) || 1639 (htype == HTYPE_ICYTHERMOSTAT) || 1640 (htype == HTYPE_TOONTHERMOSTAT) || 1641 (htype == HTYPE_AtagOne) || 1642 (htype == HTYPE_PVOUTPUT_INPUT) || 1643 (htype == HTYPE_NEST) || 1644 (htype == HTYPE_ANNATHERMOSTAT) || 1645 (htype == HTYPE_THERMOSMART) || 1646 (htype == HTYPE_Tado) || 1647 (htype == HTYPE_Tesla) || 1648 (htype == HTYPE_Netatmo) 1649 ) 1650 { 1651 if ( 1652 (username.empty()) || 1653 (password.empty()) 1654 ) 1655 return; 1656 } 1657 else if (htype == HTYPE_SolarEdgeAPI) 1658 { 1659 if ( 1660 (username.empty()) 1661 ) 1662 return; 1663 } 1664 else if (htype == HTYPE_Nest_OAuthAPI) { 1665 if ( 1666 (username == "") && 1667 (extra == "||") 1668 ) 1669 return; 1670 } 1671 else if (htype == HTYPE_HARMONY_HUB) { 1672 if ( 1673 (address.empty()) 1674 ) 1675 return; 1676 } 1677 else if (htype == HTYPE_Philips_Hue) { 1678 if ( 1679 (username.empty()) || 1680 (address.empty()) 1681 ) 1682 return; 1683 if (port == 0) 1684 port = 80; 1685 } 1686 else if (htype == HTYPE_RaspberryGPIO) { 1687 //all fine here! 1688 } 1689 else if (htype == HTYPE_SysfsGpio) { 1690 //all fine here! 1691 } 1692 else if (htype == HTYPE_Rtl433) { 1693 //all fine here! 1694 } 1695 else if (htype == HTYPE_Daikin) { 1696 //all fine here! 1697 } 1698 else if (htype == HTYPE_SBFSpot) { 1699 if (username.empty()) 1700 return; 1701 } 1702 else if (htype == HTYPE_WINDDELEN) { 1703 std::string mill_id = request::findValue(&req, "Mode1"); 1704 if ( 1705 (mill_id.empty()) || 1706 (sport.empty()) 1707 ) 1708 return; 1709 } 1710 else if (htype == HTYPE_Honeywell) { 1711 //All fine here 1712 } 1713 else if (htype == HTYPE_OpenWebNetTCP) { 1714 //All fine here 1715 } 1716 else if (htype == HTYPE_PythonPlugin) { 1717 //All fine here 1718 } 1719 else if (htype == HTYPE_GoodweAPI) { 1720 if (username.empty()) { 1721 return; 1722 } 1723 } 1724 else if (htype == HTYPE_RaspberryPCF8574) { 1725 //All fine here 1726 } 1727 else if (htype == HTYPE_OpenWebNetUSB) { 1728 //All fine here 1729 } 1730 else if (htype == HTYPE_IntergasInComfortLAN2RF) { 1731 //All fine here 1732 } 1733 else if (htype == HTYPE_EnphaseAPI) { 1734 //all fine here! 1735 } 1736 else 1737 return; 1738 1739 std::string mode1Str; 1740 std::string mode2Str; 1741 std::string mode3Str; 1742 std::string mode4Str; 1743 std::string mode5Str; 1744 std::string mode6Str; 1745 1746 root["status"] = "OK"; 1747 root["title"] = "UpdateHardware"; 1748 1749 if (htype == HTYPE_Domoticz) 1750 { 1751 if (password.size() != 32) 1752 { 1753 password = GenerateMD5Hash(password); 1754 } 1755 } 1756 1757 if ((bIsSerial) && (!bEnabled) && (sport.empty())) 1758 { 1759 //just disable the device 1760 m_sql.safe_query( 1761 "UPDATE Hardware SET Enabled=%d WHERE (ID == '%q')", 1762 (bEnabled == true) ? 1 : 0, 1763 idx.c_str() 1764 ); 1765 } 1766 else 1767 { 1768 if (htype == HTYPE_HTTPPOLLER) { 1769 m_sql.safe_query( 1770 "UPDATE Hardware SET Name='%q', Enabled=%d, Type=%d, Address='%q', Port=%d, SerialPort='%q', Username='%q', Password='%q', Extra='%q', DataTimeout=%d WHERE (ID == '%q')", 1771 name.c_str(), 1772 (senabled == "true") ? 1 : 0, 1773 htype, 1774 address.c_str(), 1775 port, 1776 sport.c_str(), 1777 username.c_str(), 1778 password.c_str(), 1779 extra.c_str(), 1780 iDataTimeout, 1781 idx.c_str() 1782 ); 1783 } 1784 else if (htype == HTYPE_PythonPlugin) { 1785 mode1Str = request::findValue(&req, "Mode1"); 1786 mode2Str = request::findValue(&req, "Mode2"); 1787 mode3Str = request::findValue(&req, "Mode3"); 1788 mode4Str = request::findValue(&req, "Mode4"); 1789 mode5Str = request::findValue(&req, "Mode5"); 1790 mode6Str = request::findValue(&req, "Mode6"); 1791 sport = request::findValue(&req, "serialport"); 1792 m_sql.safe_query( 1793 "UPDATE Hardware SET Name='%q', Enabled=%d, Type=%d, Address='%q', Port=%d, SerialPort='%q', Username='%q', Password='%q', Extra='%q', Mode1='%q', Mode2='%q', Mode3='%q', Mode4='%q', Mode5='%q', Mode6='%q', DataTimeout=%d WHERE (ID == '%q')", 1794 name.c_str(), 1795 (senabled == "true") ? 1 : 0, 1796 htype, 1797 address.c_str(), 1798 port, 1799 sport.c_str(), 1800 username.c_str(), 1801 password.c_str(), 1802 extra.c_str(), 1803 mode1Str.c_str(), mode2Str.c_str(), mode3Str.c_str(), mode4Str.c_str(), mode5Str.c_str(), mode6Str.c_str(), 1804 iDataTimeout, 1805 idx.c_str() 1806 ); 1807 } 1808 else if ( 1809 (htype == HTYPE_RFXtrx433) || 1810 (htype == HTYPE_RFXtrx868) 1811 ) 1812 { 1813 //No Extra field here, handled in CWebServer::SetRFXCOMMode 1814 m_sql.safe_query( 1815 "UPDATE Hardware SET Name='%q', Enabled=%d, Type=%d, Address='%q', Port=%d, SerialPort='%q', Username='%q', Password='%q', Mode1=%d, Mode2=%d, Mode3=%d, Mode4=%d, Mode5=%d, Mode6=%d, DataTimeout=%d WHERE (ID == '%q')", 1816 name.c_str(), 1817 (bEnabled == true) ? 1 : 0, 1818 htype, 1819 address.c_str(), 1820 port, 1821 sport.c_str(), 1822 username.c_str(), 1823 password.c_str(), 1824 mode1, mode2, mode3, mode4, mode5, mode6, 1825 iDataTimeout, 1826 idx.c_str() 1827 ); 1828 std::vector<std::vector<std::string> > result; 1829 result = m_sql.safe_query("SELECT Extra FROM Hardware WHERE ID=%q", idx.c_str()); 1830 if (!result.empty()) 1831 extra = result[0][0]; 1832 } 1833 else { 1834 m_sql.safe_query( 1835 "UPDATE Hardware SET Name='%q', Enabled=%d, Type=%d, Address='%q', Port=%d, SerialPort='%q', Username='%q', Password='%q', Extra='%q', Mode1=%d, Mode2=%d, Mode3=%d, Mode4=%d, Mode5=%d, Mode6=%d, DataTimeout=%d WHERE (ID == '%q')", 1836 name.c_str(), 1837 (bEnabled == true) ? 1 : 0, 1838 htype, 1839 address.c_str(), 1840 port, 1841 sport.c_str(), 1842 username.c_str(), 1843 password.c_str(), 1844 extra.c_str(), 1845 mode1, mode2, mode3, mode4, mode5, mode6, 1846 iDataTimeout, 1847 idx.c_str() 1848 ); 1849 } 1850 } 1851 1852 //re-add the device in our system 1853 int ID = atoi(idx.c_str()); 1854 m_mainworker.AddHardwareFromParams(ID, name, bEnabled, htype, address, port, sport, username, password, extra, mode1, mode2, mode3, mode4, mode5, mode6, iDataTimeout, true); 1855 } 1856 Cmd_GetDeviceValueOptions(WebEmSession & session,const request & req,Json::Value & root)1857 void CWebServer::Cmd_GetDeviceValueOptions(WebEmSession & session, const request& req, Json::Value &root) 1858 { 1859 if (session.rights != 2) 1860 { 1861 session.reply_status = reply::forbidden; 1862 return; //Only admin user allowed 1863 } 1864 std::string idx = request::findValue(&req, "idx"); 1865 if (idx.empty()) 1866 return; 1867 std::vector<std::string> result; 1868 result = CBasePush::DropdownOptions(atoi(idx.c_str())); 1869 if ((result.size() == 1) && result[0] == "Status") { 1870 root["result"][0]["Value"] = 0; 1871 root["result"][0]["Wording"] = result[0]; 1872 } 1873 else { 1874 int ii = 0; 1875 for (const auto & itt : result) 1876 { 1877 std::string ddOption = itt; 1878 root["result"][ii]["Value"] = ii + 1; 1879 root["result"][ii]["Wording"] = ddOption.c_str(); 1880 ii++; 1881 } 1882 1883 } 1884 root["status"] = "OK"; 1885 root["title"] = "GetDeviceValueOptions"; 1886 } 1887 Cmd_GetDeviceValueOptionWording(WebEmSession & session,const request & req,Json::Value & root)1888 void CWebServer::Cmd_GetDeviceValueOptionWording(WebEmSession & session, const request& req, Json::Value &root) 1889 { 1890 if (session.rights != 2) 1891 { 1892 session.reply_status = reply::forbidden; 1893 return; //Only admin user allowed 1894 } 1895 std::string idx = request::findValue(&req, "idx"); 1896 std::string pos = request::findValue(&req, "pos"); 1897 if ((idx.empty()) || (pos.empty())) 1898 return; 1899 std::string wording; 1900 wording = CBasePush::DropdownOptionsValue(atoi(idx.c_str()), atoi(pos.c_str())); 1901 root["wording"] = wording; 1902 root["status"] = "OK"; 1903 root["title"] = "GetDeviceValueOptions"; 1904 } 1905 Cmd_AddUserVariable(WebEmSession & session,const request & req,Json::Value & root)1906 void CWebServer::Cmd_AddUserVariable(WebEmSession & session, const request& req, Json::Value &root) 1907 { 1908 if (session.rights != 2) 1909 { 1910 session.reply_status = reply::forbidden; 1911 _log.Log(LOG_ERROR, "User: %s tried to add a uservariable!", session.username.c_str()); 1912 return; //Only admin user allowed 1913 } 1914 std::string variablename = HTMLSanitizer::Sanitize(request::findValue(&req, "vname")); 1915 std::string variablevalue = request::findValue(&req, "vvalue"); 1916 std::string variabletype = request::findValue(&req, "vtype"); 1917 1918 root["title"] = "AddUserVariable"; 1919 root["status"] = "ERR"; 1920 1921 if (!std::isdigit(variabletype[0])) 1922 { 1923 stdlower(variabletype); 1924 if (variabletype == "integer") 1925 variabletype = "0"; 1926 else if (variabletype == "float") 1927 variabletype = "1"; 1928 else if (variabletype == "string") 1929 variabletype = "2"; 1930 else if (variabletype == "date") 1931 variabletype = "3"; 1932 else if (variabletype == "time") 1933 variabletype = "4"; 1934 else 1935 { 1936 root["message"] = "Invalid variabletype " + variabletype; 1937 return; 1938 } 1939 } 1940 1941 if ( 1942 (variablename.empty()) || 1943 (variabletype.empty()) || 1944 ((variabletype != "0") && (variabletype != "1") && (variabletype != "2") && (variabletype != "3") && (variabletype != "4")) || 1945 ((variablevalue.empty()) && (variabletype != "2")) 1946 ) 1947 { 1948 root["message"] = "Invalid variabletype " + variabletype; 1949 return; 1950 } 1951 1952 std::string errorMessage; 1953 if (!m_sql.AddUserVariable(variablename, (const _eUsrVariableType)atoi(variabletype.c_str()), variablevalue, errorMessage)) 1954 { 1955 root["message"] = errorMessage; 1956 } 1957 else 1958 { 1959 root["status"] = "OK"; 1960 } 1961 } 1962 Cmd_DeleteUserVariable(WebEmSession & session,const request & req,Json::Value & root)1963 void CWebServer::Cmd_DeleteUserVariable(WebEmSession & session, const request& req, Json::Value &root) 1964 { 1965 if (session.rights != 2) 1966 { 1967 _log.Log(LOG_ERROR, "User: %s tried to delete a uservariable!", session.username.c_str()); 1968 session.reply_status = reply::forbidden; 1969 return; //Only admin user allowed 1970 } 1971 std::string idx = request::findValue(&req, "idx"); 1972 if (idx.empty()) 1973 return; 1974 1975 m_sql.DeleteUserVariable(idx); 1976 root["status"] = "OK"; 1977 root["title"] = "DeleteUserVariable"; 1978 } 1979 Cmd_UpdateUserVariable(WebEmSession & session,const request & req,Json::Value & root)1980 void CWebServer::Cmd_UpdateUserVariable(WebEmSession & session, const request& req, Json::Value &root) 1981 { 1982 if (session.rights != 2) 1983 { 1984 _log.Log(LOG_ERROR, "User: %s tried to update a uservariable!", session.username.c_str()); 1985 session.reply_status = reply::forbidden; 1986 return; //Only admin user allowed 1987 } 1988 1989 std::string idx = request::findValue(&req, "idx"); 1990 std::string variablename = HTMLSanitizer::Sanitize(request::findValue(&req, "vname")); 1991 std::string variablevalue = request::findValue(&req, "vvalue"); 1992 std::string variabletype = request::findValue(&req, "vtype"); 1993 1994 root["title"] = "UpdateUserVariable"; 1995 root["status"] = "ERR"; 1996 1997 if (!std::isdigit(variabletype[0])) 1998 { 1999 stdlower(variabletype); 2000 if (variabletype == "integer") 2001 variabletype = "0"; 2002 else if (variabletype == "float") 2003 variabletype = "1"; 2004 else if (variabletype == "string") 2005 variabletype = "2"; 2006 else if (variabletype == "date") 2007 variabletype = "3"; 2008 else if (variabletype == "time") 2009 variabletype = "4"; 2010 else 2011 { 2012 root["message"] = "Invalid variabletype " + variabletype; 2013 return; 2014 } 2015 } 2016 2017 if ( 2018 (variablename.empty()) || 2019 (variabletype.empty()) || 2020 ((variabletype != "0") && (variabletype != "1") && (variabletype != "2") && (variabletype != "3") && (variabletype != "4")) || 2021 ((variablevalue.empty()) && (variabletype != "2")) 2022 ) 2023 { 2024 root["message"] = "Invalid variabletype " + variabletype; 2025 return; 2026 } 2027 2028 std::vector<std::vector<std::string> > result; 2029 if (idx.empty()) 2030 { 2031 result = m_sql.safe_query("SELECT ID FROM UserVariables WHERE Name='%q'", variablename.c_str()); 2032 if (result.empty()) 2033 { 2034 root["message"] = "Uservariable " + variablename + " does not exist"; 2035 return; 2036 } 2037 idx = result[0][0]; 2038 } 2039 2040 result = m_sql.safe_query("SELECT Name, ValueType FROM UserVariables WHERE ID='%q'", idx.c_str()); 2041 if (result.empty()) 2042 { 2043 root["message"] = "Uservariable " + variablename + " does not exist"; 2044 return; 2045 } 2046 2047 bool bTypeNameChanged = false; 2048 if (variablename != result[0][0]) 2049 bTypeNameChanged = true; //new name 2050 else if (variabletype != result[0][1]) 2051 bTypeNameChanged = true; //new type 2052 2053 std::string errorMessage; 2054 if (!m_sql.UpdateUserVariable(idx, variablename, (const _eUsrVariableType)atoi(variabletype.c_str()), variablevalue, !bTypeNameChanged, errorMessage)) 2055 { 2056 root["message"] = errorMessage; 2057 } 2058 else { 2059 root["status"] = "OK"; 2060 if (bTypeNameChanged) 2061 { 2062 if (m_sql.m_bEnableEventSystem) 2063 m_mainworker.m_eventsystem.GetCurrentUserVariables(); 2064 } 2065 } 2066 } 2067 2068 Cmd_GetUserVariables(WebEmSession & session,const request & req,Json::Value & root)2069 void CWebServer::Cmd_GetUserVariables(WebEmSession & session, const request& req, Json::Value &root) 2070 { 2071 std::vector<std::vector<std::string> > result; 2072 result = m_sql.safe_query("SELECT ID, Name, ValueType, Value, LastUpdate FROM UserVariables"); 2073 int ii = 0; 2074 for (const auto & itt : result) 2075 { 2076 std::vector<std::string> sd = itt; 2077 root["result"][ii]["idx"] = sd[0]; 2078 root["result"][ii]["Name"] = sd[1]; 2079 root["result"][ii]["Type"] = sd[2]; 2080 root["result"][ii]["Value"] = sd[3]; 2081 root["result"][ii]["LastUpdate"] = sd[4]; 2082 ii++; 2083 } 2084 root["status"] = "OK"; 2085 root["title"] = "GetUserVariables"; 2086 } 2087 Cmd_GetUserVariable(WebEmSession & session,const request & req,Json::Value & root)2088 void CWebServer::Cmd_GetUserVariable(WebEmSession & session, const request& req, Json::Value &root) 2089 { 2090 std::string idx = request::findValue(&req, "idx"); 2091 if (idx.empty()) 2092 return; 2093 2094 int iVarID = atoi(idx.c_str()); 2095 2096 std::vector<std::vector<std::string> > result; 2097 result = m_sql.safe_query("SELECT ID, Name, ValueType, Value, LastUpdate FROM UserVariables WHERE (ID==%d)", iVarID); 2098 int ii = 0; 2099 for (const auto & itt : result) 2100 { 2101 std::vector<std::string> sd = itt; 2102 root["result"][ii]["idx"] = sd[0]; 2103 root["result"][ii]["Name"] = sd[1]; 2104 root["result"][ii]["Type"] = sd[2]; 2105 root["result"][ii]["Value"] = sd[3]; 2106 root["result"][ii]["LastUpdate"] = sd[4]; 2107 ii++; 2108 } 2109 root["status"] = "OK"; 2110 root["title"] = "GetUserVariable"; 2111 } 2112 2113 Cmd_AllowNewHardware(WebEmSession & session,const request & req,Json::Value & root)2114 void CWebServer::Cmd_AllowNewHardware(WebEmSession & session, const request& req, Json::Value &root) 2115 { 2116 if (session.rights != 2) 2117 { 2118 session.reply_status = reply::forbidden; 2119 return; //Only admin user allowed 2120 } 2121 std::string sTimeout = request::findValue(&req, "timeout"); 2122 if (sTimeout.empty()) 2123 return; 2124 root["status"] = "OK"; 2125 root["title"] = "AllowNewHardware"; 2126 2127 m_sql.AllowNewHardwareTimer(atoi(sTimeout.c_str())); 2128 } 2129 2130 Cmd_DeleteHardware(WebEmSession & session,const request & req,Json::Value & root)2131 void CWebServer::Cmd_DeleteHardware(WebEmSession & session, const request& req, Json::Value &root) 2132 { 2133 if (session.rights != 2) 2134 { 2135 session.reply_status = reply::forbidden; 2136 return; //Only admin user allowed 2137 } 2138 2139 std::string idx = request::findValue(&req, "idx"); 2140 if (idx.empty()) 2141 return; 2142 int hwID = atoi(idx.c_str()); 2143 2144 CDomoticzHardwareBase *pBaseHardware = m_mainworker.GetHardware(hwID); 2145 if ((pBaseHardware != NULL) && (pBaseHardware->HwdType == HTYPE_DomoticzInternal)) { 2146 // DomoticzInternal cannot be removed 2147 return; 2148 } 2149 2150 root["status"] = "OK"; 2151 root["title"] = "DeleteHardware"; 2152 2153 m_mainworker.RemoveDomoticzHardware(hwID); 2154 m_sql.DeleteHardware(idx); 2155 } 2156 Cmd_GetLog(WebEmSession & session,const request & req,Json::Value & root)2157 void CWebServer::Cmd_GetLog(WebEmSession & session, const request& req, Json::Value &root) 2158 { 2159 root["status"] = "OK"; 2160 root["title"] = "GetLog"; 2161 2162 time_t lastlogtime = 0; 2163 std::string slastlogtime = request::findValue(&req, "lastlogtime"); 2164 if (slastlogtime != "") 2165 { 2166 std::stringstream s_str(slastlogtime); 2167 s_str >> lastlogtime; 2168 } 2169 2170 _eLogLevel lLevel = LOG_NORM; 2171 std::string sloglevel = request::findValue(&req, "loglevel"); 2172 if (!sloglevel.empty()) 2173 { 2174 lLevel = (_eLogLevel)atoi(sloglevel.c_str()); 2175 } 2176 2177 std::list<CLogger::_tLogLineStruct> logmessages = _log.GetLog(lLevel); 2178 int ii = 0; 2179 for (const auto & itt : logmessages) 2180 { 2181 if (itt.logtime > lastlogtime) 2182 { 2183 std::stringstream szLogTime; 2184 szLogTime << itt.logtime; 2185 root["LastLogTime"] = szLogTime.str(); 2186 root["result"][ii]["level"] = static_cast<int>(itt.level); 2187 root["result"][ii]["message"] = itt.logmessage; 2188 ii++; 2189 } 2190 } 2191 } 2192 Cmd_ClearLog(WebEmSession & session,const request & req,Json::Value & root)2193 void CWebServer::Cmd_ClearLog(WebEmSession & session, const request& req, Json::Value &root) 2194 { 2195 root["status"] = "OK"; 2196 root["title"] = "ClearLog"; 2197 _log.ClearLog(); 2198 } 2199 2200 //Plan Functions Cmd_AddPlan(WebEmSession & session,const request & req,Json::Value & root)2201 void CWebServer::Cmd_AddPlan(WebEmSession & session, const request& req, Json::Value &root) 2202 { 2203 if (session.rights != 2) 2204 { 2205 session.reply_status = reply::forbidden; 2206 return; //Only admin user allowed 2207 } 2208 2209 std::string name = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 2210 if (name.empty()) 2211 { 2212 session.reply_status = reply::bad_request; 2213 } 2214 2215 root["status"] = "OK"; 2216 root["title"] = "AddPlan"; 2217 m_sql.safe_query( 2218 "INSERT INTO Plans (Name) VALUES ('%q')", 2219 name.c_str() 2220 ); 2221 std::vector<std::vector<std::string> > result; 2222 result = m_sql.safe_query("SELECT MAX(ID) FROM Plans"); 2223 if (!result.empty()) 2224 { 2225 std::vector<std::string> sd = result[0]; 2226 int ID = atoi(sd[0].c_str()); 2227 2228 root["idx"] = ID; // OTO output the created ID for easier management on the caller side (if automated) 2229 } 2230 } 2231 Cmd_UpdatePlan(WebEmSession & session,const request & req,Json::Value & root)2232 void CWebServer::Cmd_UpdatePlan(WebEmSession & session, const request& req, Json::Value &root) 2233 { 2234 if (session.rights != 2) 2235 { 2236 session.reply_status = reply::forbidden; 2237 return; //Only admin user allowed 2238 } 2239 2240 std::string idx = request::findValue(&req, "idx"); 2241 if (idx.empty()) 2242 return; 2243 std::string name = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 2244 if (name.empty()) 2245 { 2246 session.reply_status = reply::bad_request; 2247 return; 2248 } 2249 2250 root["status"] = "OK"; 2251 root["title"] = "UpdatePlan"; 2252 2253 m_sql.safe_query( 2254 "UPDATE Plans SET Name='%q' WHERE (ID == '%q')", 2255 name.c_str(), 2256 idx.c_str() 2257 ); 2258 } 2259 Cmd_DeletePlan(WebEmSession & session,const request & req,Json::Value & root)2260 void CWebServer::Cmd_DeletePlan(WebEmSession & session, const request& req, Json::Value &root) 2261 { 2262 if (session.rights != 2) 2263 { 2264 session.reply_status = reply::forbidden; 2265 return; //Only admin user allowed 2266 } 2267 2268 std::string idx = request::findValue(&req, "idx"); 2269 if (idx.empty()) 2270 return; 2271 root["status"] = "OK"; 2272 root["title"] = "DeletePlan"; 2273 m_sql.safe_query( 2274 "DELETE FROM DeviceToPlansMap WHERE (PlanID == '%q')", 2275 idx.c_str() 2276 ); 2277 m_sql.safe_query( 2278 "DELETE FROM Plans WHERE (ID == '%q')", 2279 idx.c_str() 2280 ); 2281 } 2282 Cmd_GetUnusedPlanDevices(WebEmSession & session,const request & req,Json::Value & root)2283 void CWebServer::Cmd_GetUnusedPlanDevices(WebEmSession & session, const request& req, Json::Value &root) 2284 { 2285 root["status"] = "OK"; 2286 root["title"] = "GetUnusedPlanDevices"; 2287 std::string sunique = request::findValue(&req, "unique"); 2288 if (sunique.empty()) 2289 return; 2290 int iUnique = (sunique == "true") ? 1 : 0; 2291 int ii = 0; 2292 2293 std::vector<std::vector<std::string> > result; 2294 std::vector<std::vector<std::string> > result2; 2295 result = m_sql.safe_query("SELECT T1.[ID], T1.[Name], T1.[Type], T1.[SubType], T2.[Name] AS HardwareName FROM DeviceStatus as T1, Hardware as T2 WHERE (T1.[Used]==1) AND (T2.[ID]==T1.[HardwareID]) ORDER BY T2.[Name], T1.[Name]"); 2296 if (!result.empty()) 2297 { 2298 for (const auto & itt : result) 2299 { 2300 std::vector<std::string> sd = itt; 2301 2302 bool bDoAdd = true; 2303 if (iUnique) 2304 { 2305 result2 = m_sql.safe_query("SELECT ID FROM DeviceToPlansMap WHERE (DeviceRowID=='%q') AND (DevSceneType==0)", 2306 sd[0].c_str()); 2307 bDoAdd = (result2.size() == 0); 2308 } 2309 if (bDoAdd) 2310 { 2311 int _dtype = atoi(sd[2].c_str()); 2312 std::string Name = "[" + sd[4] + "] " + sd[1] + " (" + RFX_Type_Desc(_dtype, 1) + "/" + RFX_Type_SubType_Desc(_dtype, atoi(sd[3].c_str())) + ")"; 2313 root["result"][ii]["type"] = 0; 2314 root["result"][ii]["idx"] = sd[0]; 2315 root["result"][ii]["Name"] = Name; 2316 ii++; 2317 } 2318 } 2319 } 2320 //Add Scenes 2321 result = m_sql.safe_query("SELECT ID, Name FROM Scenes ORDER BY Name"); 2322 if (!result.empty()) 2323 { 2324 for (const auto & itt : result) 2325 { 2326 std::vector<std::string> sd = itt; 2327 2328 bool bDoAdd = true; 2329 if (iUnique) 2330 { 2331 result2 = m_sql.safe_query("SELECT ID FROM DeviceToPlansMap WHERE (DeviceRowID=='%q') AND (DevSceneType==1)", 2332 sd[0].c_str()); 2333 bDoAdd = (result2.size() == 0); 2334 } 2335 if (bDoAdd) 2336 { 2337 root["result"][ii]["type"] = 1; 2338 root["result"][ii]["idx"] = sd[0]; 2339 std::string sname = "[Scene] " + sd[1]; 2340 root["result"][ii]["Name"] = sname; 2341 ii++; 2342 } 2343 } 2344 } 2345 } 2346 Cmd_AddPlanActiveDevice(WebEmSession & session,const request & req,Json::Value & root)2347 void CWebServer::Cmd_AddPlanActiveDevice(WebEmSession & session, const request& req, Json::Value &root) 2348 { 2349 if (session.rights != 2) 2350 { 2351 session.reply_status = reply::forbidden; 2352 return; //Only admin user allowed 2353 } 2354 2355 std::string idx = request::findValue(&req, "idx"); 2356 std::string sactivetype = request::findValue(&req, "activetype"); 2357 std::string activeidx = request::findValue(&req, "activeidx"); 2358 if ( 2359 (idx.empty()) || 2360 (sactivetype.empty()) || 2361 (activeidx.empty()) 2362 ) 2363 return; 2364 root["status"] = "OK"; 2365 root["title"] = "AddPlanActiveDevice"; 2366 2367 int activetype = atoi(sactivetype.c_str()); 2368 2369 //check if it is not already there 2370 std::vector<std::vector<std::string> > result; 2371 result = m_sql.safe_query("SELECT ID FROM DeviceToPlansMap WHERE (DeviceRowID=='%q') AND (DevSceneType==%d) AND (PlanID=='%q')", 2372 activeidx.c_str(), activetype, idx.c_str()); 2373 if (result.empty()) 2374 { 2375 m_sql.safe_query( 2376 "INSERT INTO DeviceToPlansMap (DevSceneType,DeviceRowID, PlanID) VALUES (%d,'%q','%q')", 2377 activetype, 2378 activeidx.c_str(), 2379 idx.c_str() 2380 ); 2381 } 2382 } 2383 Cmd_GetPlanDevices(WebEmSession & session,const request & req,Json::Value & root)2384 void CWebServer::Cmd_GetPlanDevices(WebEmSession & session, const request& req, Json::Value &root) 2385 { 2386 std::string idx = request::findValue(&req, "idx"); 2387 if (idx.empty()) 2388 return; 2389 root["status"] = "OK"; 2390 root["title"] = "GetPlanDevices"; 2391 2392 std::vector<std::vector<std::string> > result; 2393 result = m_sql.safe_query("SELECT ID, DevSceneType, DeviceRowID, [Order] FROM DeviceToPlansMap WHERE (PlanID=='%q') ORDER BY [Order]", 2394 idx.c_str()); 2395 if (!result.empty()) 2396 { 2397 int ii = 0; 2398 for (const auto & itt : result) 2399 { 2400 std::vector<std::string> sd = itt; 2401 2402 std::string ID = sd[0]; 2403 int DevSceneType = atoi(sd[1].c_str()); 2404 std::string DevSceneRowID = sd[2]; 2405 2406 std::string Name = ""; 2407 if (DevSceneType == 0) 2408 { 2409 std::vector<std::vector<std::string> > result2; 2410 result2 = m_sql.safe_query("SELECT Name FROM DeviceStatus WHERE (ID=='%q')", 2411 DevSceneRowID.c_str()); 2412 if (!result2.empty()) 2413 { 2414 Name = result2[0][0]; 2415 } 2416 } 2417 else 2418 { 2419 std::vector<std::vector<std::string> > result2; 2420 result2 = m_sql.safe_query("SELECT Name FROM Scenes WHERE (ID=='%q')", 2421 DevSceneRowID.c_str()); 2422 if (!result2.empty()) 2423 { 2424 Name = "[Scene] " + result2[0][0]; 2425 } 2426 } 2427 if (Name != "") 2428 { 2429 root["result"][ii]["idx"] = ID; 2430 root["result"][ii]["devidx"] = DevSceneRowID; 2431 root["result"][ii]["type"] = DevSceneType; 2432 root["result"][ii]["DevSceneRowID"] = DevSceneRowID; 2433 root["result"][ii]["order"] = sd[3]; 2434 root["result"][ii]["Name"] = Name; 2435 ii++; 2436 } 2437 } 2438 } 2439 } 2440 Cmd_DeletePlanDevice(WebEmSession & session,const request & req,Json::Value & root)2441 void CWebServer::Cmd_DeletePlanDevice(WebEmSession & session, const request& req, Json::Value &root) 2442 { 2443 if (session.rights != 2) 2444 { 2445 session.reply_status = reply::forbidden; 2446 return; //Only admin user allowed 2447 } 2448 std::string idx = request::findValue(&req, "idx"); 2449 if (idx.empty()) 2450 return; 2451 root["status"] = "OK"; 2452 root["title"] = "DeletePlanDevice"; 2453 m_sql.safe_query("DELETE FROM DeviceToPlansMap WHERE (ID == '%q')", idx.c_str()); 2454 } 2455 Cmd_SetPlanDeviceCoords(WebEmSession & session,const request & req,Json::Value & root)2456 void CWebServer::Cmd_SetPlanDeviceCoords(WebEmSession & session, const request& req, Json::Value &root) 2457 { 2458 std::string idx = request::findValue(&req, "idx"); 2459 std::string planidx = request::findValue(&req, "planidx"); 2460 std::string xoffset = request::findValue(&req, "xoffset"); 2461 std::string yoffset = request::findValue(&req, "yoffset"); 2462 std::string type = request::findValue(&req, "DevSceneType"); 2463 if ((idx.empty()) || (planidx.empty()) || (xoffset.empty()) || (yoffset.empty())) 2464 return; 2465 if (type != "1") type = "0"; // 0 = Device, 1 = Scene/Group 2466 root["status"] = "OK"; 2467 root["title"] = "SetPlanDeviceCoords"; 2468 m_sql.safe_query("UPDATE DeviceToPlansMap SET [XOffset] = '%q', [YOffset] = '%q' WHERE (DeviceRowID='%q') and (PlanID='%q') and (DevSceneType='%q')", 2469 xoffset.c_str(), yoffset.c_str(), idx.c_str(), planidx.c_str(), type.c_str()); 2470 _log.Log(LOG_STATUS, "(Floorplan) Device '%s' coordinates set to '%s,%s' in plan '%s'.", idx.c_str(), xoffset.c_str(), yoffset.c_str(), planidx.c_str()); 2471 } 2472 Cmd_DeleteAllPlanDevices(WebEmSession & session,const request & req,Json::Value & root)2473 void CWebServer::Cmd_DeleteAllPlanDevices(WebEmSession & session, const request& req, Json::Value &root) 2474 { 2475 if (session.rights != 2) 2476 { 2477 session.reply_status = reply::forbidden; 2478 return; //Only admin user allowed 2479 } 2480 std::string idx = request::findValue(&req, "idx"); 2481 if (idx.empty()) 2482 return; 2483 root["status"] = "OK"; 2484 root["title"] = "DeleteAllPlanDevices"; 2485 m_sql.safe_query("DELETE FROM DeviceToPlansMap WHERE (PlanID == '%q')", idx.c_str()); 2486 } 2487 Cmd_ChangePlanOrder(WebEmSession & session,const request & req,Json::Value & root)2488 void CWebServer::Cmd_ChangePlanOrder(WebEmSession & session, const request& req, Json::Value &root) 2489 { 2490 std::string idx = request::findValue(&req, "idx"); 2491 if (idx.empty()) 2492 return; 2493 std::string sway = request::findValue(&req, "way"); 2494 if (sway.empty()) 2495 return; 2496 bool bGoUp = (sway == "0"); 2497 2498 std::string aOrder, oID, oOrder; 2499 2500 std::vector<std::vector<std::string> > result; 2501 result = m_sql.safe_query("SELECT [Order] FROM Plans WHERE (ID=='%q')", 2502 idx.c_str()); 2503 if (result.empty()) 2504 return; 2505 aOrder = result[0][0]; 2506 2507 if (!bGoUp) 2508 { 2509 //Get next device order 2510 result = m_sql.safe_query("SELECT ID, [Order] FROM Plans WHERE ([Order]>'%q') ORDER BY [Order] ASC", 2511 aOrder.c_str()); 2512 if (result.empty()) 2513 return; 2514 oID = result[0][0]; 2515 oOrder = result[0][1]; 2516 } 2517 else 2518 { 2519 //Get previous device order 2520 result = m_sql.safe_query("SELECT ID, [Order] FROM Plans WHERE ([Order]<'%q') ORDER BY [Order] DESC", 2521 aOrder.c_str()); 2522 if (result.empty()) 2523 return; 2524 oID = result[0][0]; 2525 oOrder = result[0][1]; 2526 } 2527 //Swap them 2528 root["status"] = "OK"; 2529 root["title"] = "ChangePlanOrder"; 2530 2531 m_sql.safe_query("UPDATE Plans SET [Order] = '%q' WHERE (ID='%q')", 2532 oOrder.c_str(), idx.c_str()); 2533 m_sql.safe_query("UPDATE Plans SET [Order] = '%q' WHERE (ID='%q')", 2534 aOrder.c_str(), oID.c_str()); 2535 } 2536 Cmd_ChangePlanDeviceOrder(WebEmSession & session,const request & req,Json::Value & root)2537 void CWebServer::Cmd_ChangePlanDeviceOrder(WebEmSession & session, const request& req, Json::Value &root) 2538 { 2539 std::string planid = request::findValue(&req, "planid"); 2540 std::string idx = request::findValue(&req, "idx"); 2541 std::string sway = request::findValue(&req, "way"); 2542 if ( 2543 (planid.empty()) || 2544 (idx.empty()) || 2545 (sway.empty()) 2546 ) 2547 return; 2548 bool bGoUp = (sway == "0"); 2549 2550 std::string aOrder, oID, oOrder; 2551 2552 std::vector<std::vector<std::string> > result; 2553 result = m_sql.safe_query("SELECT [Order] FROM DeviceToPlansMap WHERE ((ID=='%q') AND (PlanID=='%q'))", 2554 idx.c_str(), planid.c_str()); 2555 if (result.empty()) 2556 return; 2557 aOrder = result[0][0]; 2558 2559 if (!bGoUp) 2560 { 2561 //Get next device order 2562 result = m_sql.safe_query("SELECT ID, [Order] FROM DeviceToPlansMap WHERE (([Order]>'%q') AND (PlanID=='%q')) ORDER BY [Order] ASC", 2563 aOrder.c_str(), planid.c_str()); 2564 if (result.empty()) 2565 return; 2566 oID = result[0][0]; 2567 oOrder = result[0][1]; 2568 } 2569 else 2570 { 2571 //Get previous device order 2572 result = m_sql.safe_query("SELECT ID, [Order] FROM DeviceToPlansMap WHERE (([Order]<'%q') AND (PlanID=='%q')) ORDER BY [Order] DESC", 2573 aOrder.c_str(), planid.c_str()); 2574 if (result.empty()) 2575 return; 2576 oID = result[0][0]; 2577 oOrder = result[0][1]; 2578 } 2579 //Swap them 2580 root["status"] = "OK"; 2581 root["title"] = "ChangePlanOrder"; 2582 2583 m_sql.safe_query("UPDATE DeviceToPlansMap SET [Order] = '%q' WHERE (ID='%q')", 2584 oOrder.c_str(), idx.c_str()); 2585 m_sql.safe_query("UPDATE DeviceToPlansMap SET [Order] = '%q' WHERE (ID='%q')", 2586 aOrder.c_str(), oID.c_str()); 2587 } 2588 Cmd_GetVersion(WebEmSession & session,const request & req,Json::Value & root)2589 void CWebServer::Cmd_GetVersion(WebEmSession & session, const request& req, Json::Value &root) 2590 { 2591 root["status"] = "OK"; 2592 root["title"] = "GetVersion"; 2593 root["version"] = szAppVersion; 2594 root["hash"] = szAppHash; 2595 root["build_time"] = szAppDate; 2596 CdzVents* dzvents = CdzVents::GetInstance(); 2597 root["dzvents_version"] = dzvents->GetVersion(); 2598 root["python_version"] = szPyVersion; 2599 2600 if (session.rights != 2) 2601 { 2602 //only admin users will receive the update notification 2603 root["UseUpdate"] = false; 2604 root["HaveUpdate"] = false; 2605 } 2606 else 2607 { 2608 root["UseUpdate"] = g_bUseUpdater; 2609 root["HaveUpdate"] = m_mainworker.IsUpdateAvailable(false); 2610 root["DomoticzUpdateURL"] = m_mainworker.m_szDomoticzUpdateURL; 2611 root["SystemName"] = m_mainworker.m_szSystemName; 2612 root["Revision"] = m_mainworker.m_iRevision; 2613 } 2614 } 2615 Cmd_GetAuth(WebEmSession & session,const request & req,Json::Value & root)2616 void CWebServer::Cmd_GetAuth(WebEmSession & session, const request& req, Json::Value &root) 2617 { 2618 root["status"] = "OK"; 2619 root["title"] = "GetAuth"; 2620 if (session.rights != -1) 2621 { 2622 root["version"] = szAppVersion; 2623 } 2624 root["user"] = session.username; 2625 root["rights"] = session.rights; 2626 } 2627 Cmd_GetUptime(WebEmSession & session,const request & req,Json::Value & root)2628 void CWebServer::Cmd_GetUptime(WebEmSession & session, const request& req, Json::Value &root) 2629 { 2630 //this is used in the about page, we are going to round the seconds a bit to display nicer 2631 time_t atime = mytime(NULL); 2632 time_t tuptime = atime - m_StartTime; 2633 //round to 5 seconds (nicer in about page) 2634 tuptime = ((tuptime / 5) * 5) + 5; 2635 int days, hours, minutes, seconds; 2636 days = (int)(tuptime / 86400); 2637 tuptime -= (days * 86400); 2638 hours = (int)(tuptime / 3600); 2639 tuptime -= (hours * 3600); 2640 minutes = (int)(tuptime / 60); 2641 tuptime -= (minutes * 60); 2642 seconds = (int)tuptime; 2643 root["status"] = "OK"; 2644 root["title"] = "GetUptime"; 2645 root["days"] = days; 2646 root["hours"] = hours; 2647 root["minutes"] = minutes; 2648 root["seconds"] = seconds; 2649 } 2650 Cmd_GetActualHistory(WebEmSession & session,const request & req,Json::Value & root)2651 void CWebServer::Cmd_GetActualHistory(WebEmSession & session, const request& req, Json::Value &root) 2652 { 2653 root["status"] = "OK"; 2654 root["title"] = "GetActualHistory"; 2655 2656 std::string historyfile = szUserDataFolder + "History.txt"; 2657 2658 std::ifstream infile; 2659 int ii = 0; 2660 infile.open(historyfile.c_str()); 2661 std::string sLine; 2662 if (infile.is_open()) 2663 { 2664 while (!infile.eof()) 2665 { 2666 getline(infile, sLine); 2667 root["LastLogTime"] = ""; 2668 if (sLine.find("Version ") == 0) 2669 root["result"][ii]["level"] = 1; 2670 else 2671 root["result"][ii]["level"] = 0; 2672 root["result"][ii]["message"] = sLine; 2673 ii++; 2674 } 2675 } 2676 } 2677 Cmd_GetNewHistory(WebEmSession & session,const request & req,Json::Value & root)2678 void CWebServer::Cmd_GetNewHistory(WebEmSession & session, const request& req, Json::Value &root) 2679 { 2680 root["status"] = "OK"; 2681 root["title"] = "GetNewHistory"; 2682 2683 std::string historyfile; 2684 int nValue; 2685 m_sql.GetPreferencesVar("ReleaseChannel", nValue); 2686 bool bIsBetaChannel = (nValue != 0); 2687 2688 std::string szHistoryURL = "https://www.domoticz.com/download.php?channel=stable&type=history"; 2689 if (bIsBetaChannel) 2690 { 2691 utsname my_uname; 2692 if (uname(&my_uname) < 0) 2693 return; 2694 2695 std::string systemname = my_uname.sysname; 2696 std::string machine = my_uname.machine; 2697 std::transform(systemname.begin(), systemname.end(), systemname.begin(), ::tolower); 2698 2699 if (machine == "armv6l") 2700 { 2701 //Seems like old arm systems can also use the new arm build 2702 machine = "armv7l"; 2703 } 2704 2705 if (((machine != "armv6l") && (machine != "armv7l") && (systemname != "windows") && (machine != "x86_64") && (machine != "aarch64")) || (strstr(my_uname.release, "ARCH+") != NULL)) 2706 szHistoryURL = "https://www.domoticz.com/download.php?channel=beta&type=history"; 2707 else 2708 szHistoryURL = "https://www.domoticz.com/download.php?channel=beta&type=history&system=" + systemname + "&machine=" + machine; 2709 } 2710 if (!HTTPClient::GET(szHistoryURL, historyfile)) 2711 { 2712 historyfile = "Unable to get Online History document !!"; 2713 } 2714 2715 std::istringstream stream(historyfile); 2716 std::string sLine; 2717 int ii = 0; 2718 while (std::getline(stream, sLine)) 2719 { 2720 root["LastLogTime"] = ""; 2721 if (sLine.find("Version ") == 0) 2722 root["result"][ii]["level"] = 1; 2723 else 2724 root["result"][ii]["level"] = 0; 2725 root["result"][ii]["message"] = sLine; 2726 ii++; 2727 } 2728 } 2729 Cmd_GetConfig(WebEmSession & session,const request & req,Json::Value & root)2730 void CWebServer::Cmd_GetConfig(WebEmSession & session, const request& req, Json::Value &root) 2731 { 2732 root["status"] = "OK"; 2733 root["title"] = "GetConfig"; 2734 2735 bool bHaveUser = (session.username != ""); 2736 //int urights = 3; 2737 unsigned long UserID = 0; 2738 if (bHaveUser) 2739 { 2740 int iUser = FindUser(session.username.c_str()); 2741 if (iUser != -1) 2742 { 2743 //urights = static_cast<int>(m_users[iUser].userrights); 2744 UserID = m_users[iUser].ID; 2745 } 2746 } 2747 2748 int nValue; 2749 std::string sValue; 2750 2751 if (m_sql.GetPreferencesVar("Language", sValue)) 2752 { 2753 root["language"] = sValue; 2754 } 2755 if (m_sql.GetPreferencesVar("DegreeDaysBaseTemperature", sValue)) 2756 { 2757 root["DegreeDaysBaseTemperature"] = atof(sValue.c_str()); 2758 } 2759 2760 nValue = 0; 2761 int iDashboardType = 0; 2762 m_sql.GetPreferencesVar("DashboardType", iDashboardType); 2763 root["DashboardType"] = iDashboardType; 2764 m_sql.GetPreferencesVar("MobileType", nValue); 2765 root["MobileType"] = nValue; 2766 2767 nValue = 1; 2768 m_sql.GetPreferencesVar("5MinuteHistoryDays", nValue); 2769 root["FiveMinuteHistoryDays"] = nValue; 2770 2771 nValue = 1; 2772 m_sql.GetPreferencesVar("ShowUpdateEffect", nValue); 2773 root["result"]["ShowUpdatedEffect"] = (nValue == 1); 2774 2775 root["AllowWidgetOrdering"] = m_sql.m_bAllowWidgetOrdering; 2776 2777 root["WindScale"] = m_sql.m_windscale*10.0f; 2778 root["WindSign"] = m_sql.m_windsign; 2779 root["TempScale"] = m_sql.m_tempscale; 2780 root["TempSign"] = m_sql.m_tempsign; 2781 2782 #ifndef NOCLOUD 2783 bool bEnableTabProxy = request::get_req_header(&req, "X-From-MyDomoticz") != NULL; 2784 #else 2785 bool bEnableTabProxy = false; 2786 #endif 2787 int bEnableTabDashboard = 1; 2788 int bEnableTabFloorplans = 1; 2789 int bEnableTabLight = 1; 2790 int bEnableTabScenes = 1; 2791 int bEnableTabTemp = 1; 2792 int bEnableTabWeather = 1; 2793 int bEnableTabUtility = 1; 2794 int bEnableTabCustom = 1; 2795 2796 std::vector<std::vector<std::string> > result; 2797 2798 if ((UserID != 0) && (UserID != 10000)) 2799 { 2800 result = m_sql.safe_query("SELECT TabsEnabled FROM Users WHERE (ID==%lu)", 2801 UserID); 2802 if (!result.empty()) 2803 { 2804 int TabsEnabled = atoi(result[0][0].c_str()); 2805 bEnableTabLight = (TabsEnabled&(1 << 0)); 2806 bEnableTabScenes = (TabsEnabled&(1 << 1)); 2807 bEnableTabTemp = (TabsEnabled&(1 << 2)); 2808 bEnableTabWeather = (TabsEnabled&(1 << 3)); 2809 bEnableTabUtility = (TabsEnabled&(1 << 4)); 2810 bEnableTabCustom = (TabsEnabled&(1 << 5)); 2811 bEnableTabFloorplans = (TabsEnabled&(1 << 6)); 2812 } 2813 } 2814 else 2815 { 2816 m_sql.GetPreferencesVar("EnableTabFloorplans", bEnableTabFloorplans); 2817 m_sql.GetPreferencesVar("EnableTabLights", bEnableTabLight); 2818 m_sql.GetPreferencesVar("EnableTabScenes", bEnableTabScenes); 2819 m_sql.GetPreferencesVar("EnableTabTemp", bEnableTabTemp); 2820 m_sql.GetPreferencesVar("EnableTabWeather", bEnableTabWeather); 2821 m_sql.GetPreferencesVar("EnableTabUtility", bEnableTabUtility); 2822 m_sql.GetPreferencesVar("EnableTabCustom", bEnableTabCustom); 2823 } 2824 if (iDashboardType == 3) 2825 { 2826 //Floorplan , no need to show a tab floorplan 2827 bEnableTabFloorplans = 0; 2828 } 2829 root["result"]["EnableTabProxy"] = bEnableTabProxy; 2830 root["result"]["EnableTabDashboard"] = bEnableTabDashboard != 0; 2831 root["result"]["EnableTabFloorplans"] = bEnableTabFloorplans != 0; 2832 root["result"]["EnableTabLights"] = bEnableTabLight != 0; 2833 root["result"]["EnableTabScenes"] = bEnableTabScenes != 0; 2834 root["result"]["EnableTabTemp"] = bEnableTabTemp != 0; 2835 root["result"]["EnableTabWeather"] = bEnableTabWeather != 0; 2836 root["result"]["EnableTabUtility"] = bEnableTabUtility != 0; 2837 root["result"]["EnableTabCustom"] = bEnableTabCustom != 0; 2838 2839 if (bEnableTabCustom) 2840 { 2841 //Add custom templates 2842 DIR *lDir; 2843 struct dirent *ent; 2844 std::string templatesFolder = szWWWFolder + "/templates"; 2845 int iFile = 0; 2846 if ((lDir = opendir(templatesFolder.c_str())) != NULL) 2847 { 2848 while ((ent = readdir(lDir)) != NULL) 2849 { 2850 std::string filename = ent->d_name; 2851 size_t pos = filename.find(".htm"); 2852 if (pos != std::string::npos) 2853 { 2854 std::string shortfile = filename.substr(0, pos); 2855 root["result"]["templates"][iFile++] = shortfile; 2856 } 2857 } 2858 closedir(lDir); 2859 } 2860 } 2861 } 2862 Cmd_GetLocation(WebEmSession & session,const request & req,Json::Value & root)2863 void CWebServer::Cmd_GetLocation(WebEmSession& session, const request& req, Json::Value& root) 2864 { 2865 if (session.rights == -1) 2866 { 2867 session.reply_status = reply::forbidden; 2868 return;//Only auth user allowed 2869 } 2870 std::string Latitude = "1"; 2871 std::string Longitude = "1"; 2872 std::string sValue; 2873 if (m_sql.GetPreferencesVar("Location", sValue)) 2874 { 2875 std::vector<std::string> strarray; 2876 StringSplit(sValue, ";", strarray); 2877 2878 if (strarray.size() == 2) 2879 { 2880 Latitude = strarray[0]; 2881 Longitude = strarray[1]; 2882 } 2883 } 2884 root["Latitude"] = Latitude; 2885 root["Longitude"] = Longitude; 2886 } 2887 Cmd_SendNotification(WebEmSession & session,const request & req,Json::Value & root)2888 void CWebServer::Cmd_SendNotification(WebEmSession & session, const request& req, Json::Value &root) 2889 { 2890 std::string subject = request::findValue(&req, "subject"); 2891 std::string body = request::findValue(&req, "body"); 2892 std::string subsystem = request::findValue(&req, "subsystem"); 2893 if ( 2894 (subject.empty()) || 2895 (body.empty()) 2896 ) 2897 return; 2898 if (subsystem.empty()) subsystem = NOTIFYALL; 2899 //Add to queue 2900 if (m_notifications.SendMessage(0, std::string(""), subsystem, subject, body, std::string(""), 1, std::string(""), false)) { 2901 root["status"] = "OK"; 2902 } 2903 root["title"] = "SendNotification"; 2904 } 2905 Cmd_EmailCameraSnapshot(WebEmSession & session,const request & req,Json::Value & root)2906 void CWebServer::Cmd_EmailCameraSnapshot(WebEmSession & session, const request& req, Json::Value &root) 2907 { 2908 std::string camidx = request::findValue(&req, "camidx"); 2909 std::string subject = request::findValue(&req, "subject"); 2910 if ( 2911 (camidx.empty()) || 2912 (subject.empty()) 2913 ) 2914 return; 2915 //Add to queue 2916 m_sql.AddTaskItem(_tTaskItem::EmailCameraSnapshot(1, camidx, subject)); 2917 root["status"] = "OK"; 2918 root["title"] = "Email Camera Snapshot"; 2919 } 2920 Cmd_UpdateDevice(WebEmSession & session,const request & req,Json::Value & root)2921 void CWebServer::Cmd_UpdateDevice(WebEmSession & session, const request& req, Json::Value &root) 2922 { 2923 if (session.rights < 1) 2924 { 2925 session.reply_status = reply::forbidden; 2926 return; //only user or higher allowed 2927 } 2928 2929 std::string idx = request::findValue(&req, "idx"); 2930 2931 if (!IsIdxForUser(&session, atoi(idx.c_str()))) 2932 { 2933 _log.Log(LOG_ERROR, "User: %s tried to update an Unauthorized device!", session.username.c_str()); 2934 session.reply_status = reply::forbidden; 2935 return; 2936 } 2937 2938 std::string hid = request::findValue(&req, "hid"); 2939 std::string did = request::findValue(&req, "did"); 2940 std::string dunit = request::findValue(&req, "dunit"); 2941 std::string dtype = request::findValue(&req, "dtype"); 2942 std::string dsubtype = request::findValue(&req, "dsubtype"); 2943 2944 std::string nvalue = request::findValue(&req, "nvalue"); 2945 std::string svalue = request::findValue(&req, "svalue"); 2946 std::string ptrigger = request::findValue(&req, "parsetrigger"); 2947 2948 bool parseTrigger = (ptrigger != "false"); 2949 2950 if ((nvalue.empty() && svalue.empty())) 2951 { 2952 return; 2953 } 2954 2955 int signallevel = 12; 2956 int batterylevel = 255; 2957 2958 if (idx.empty()) 2959 { 2960 //No index supplied, check if raw parameters where supplied 2961 if ( 2962 (hid.empty()) || 2963 (did.empty()) || 2964 (dunit.empty()) || 2965 (dtype.empty()) || 2966 (dsubtype.empty()) 2967 ) 2968 return; 2969 } 2970 else 2971 { 2972 //Get the raw device parameters 2973 std::vector<std::vector<std::string> > result; 2974 result = m_sql.safe_query("SELECT HardwareID, DeviceID, Unit, Type, SubType FROM DeviceStatus WHERE (ID=='%q')", 2975 idx.c_str()); 2976 if (result.empty()) 2977 return; 2978 hid = result[0][0]; 2979 did = result[0][1]; 2980 dunit = result[0][2]; 2981 dtype = result[0][3]; 2982 dsubtype = result[0][4]; 2983 } 2984 2985 int HardwareID = atoi(hid.c_str()); 2986 std::string DeviceID = did; 2987 int unit = atoi(dunit.c_str()); 2988 int devType = atoi(dtype.c_str()); 2989 int subType = atoi(dsubtype.c_str()); 2990 2991 //uint64_t ulIdx = std::strtoull(idx.c_str(), nullptr, 10); 2992 2993 int invalue = atoi(nvalue.c_str()); 2994 2995 std::string sSignalLevel = request::findValue(&req, "rssi"); 2996 if (sSignalLevel != "") 2997 { 2998 signallevel = atoi(sSignalLevel.c_str()); 2999 } 3000 std::string sBatteryLevel = request::findValue(&req, "battery"); 3001 if (sBatteryLevel != "") 3002 { 3003 batterylevel = atoi(sBatteryLevel.c_str()); 3004 } 3005 if (m_mainworker.UpdateDevice(HardwareID, DeviceID, unit, devType, subType, invalue, svalue, signallevel, batterylevel, parseTrigger)) 3006 { 3007 root["status"] = "OK"; 3008 root["title"] = "Update Device"; 3009 } 3010 } 3011 Cmd_UpdateDevices(WebEmSession & session,const request & req,Json::Value & root)3012 void CWebServer::Cmd_UpdateDevices(WebEmSession & session, const request& req, Json::Value &root) 3013 { 3014 std::string script = request::findValue(&req, "script"); 3015 if (script.empty()) 3016 { 3017 return; 3018 } 3019 std::string content = req.content; 3020 3021 std::vector<std::string> allParameters; 3022 3023 // Keep the url content on the right of the '?' 3024 std::vector<std::string> allParts; 3025 StringSplit(req.uri, "?", allParts); 3026 if (!allParts.empty()) 3027 { 3028 // Split all url parts separated by a '&' 3029 StringSplit(allParts[1], "&", allParameters); 3030 } 3031 3032 CLuaHandler luaScript; 3033 bool ret = luaScript.executeLuaScript(script, content, allParameters); 3034 if (ret) 3035 { 3036 root["status"] = "OK"; 3037 root["title"] = "Update Device"; 3038 } 3039 } 3040 Cmd_CustomEvent(WebEmSession & session,const request & req,Json::Value & root)3041 void CWebServer::Cmd_CustomEvent(WebEmSession& session, const request& req, Json::Value& root) 3042 { 3043 if (session.rights < 1) 3044 { 3045 session.reply_status = reply::forbidden; 3046 return; //only user or higher allowed 3047 } 3048 Json::Value eventInfo; 3049 eventInfo["name"] = request::findValue(&req, "event"); 3050 eventInfo["data"] = request::findValue(&req, "data"); 3051 3052 if (eventInfo["name"].empty()) 3053 { 3054 return; 3055 } 3056 3057 m_mainworker.m_notificationsystem.Notify(Notification::DZ_CUSTOM, Notification::STATUS_INFO, JSonToRawString(eventInfo)); 3058 3059 root["status"] = "OK"; 3060 root["title"] = "Custom Event"; 3061 } 3062 Cmd_SetThermostatState(WebEmSession & session,const request & req,Json::Value & root)3063 void CWebServer::Cmd_SetThermostatState(WebEmSession & session, const request& req, Json::Value &root) 3064 { 3065 std::string sstate = request::findValue(&req, "state"); 3066 std::string idx = request::findValue(&req, "idx"); 3067 std::string name = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 3068 3069 if ( 3070 (idx.empty()) || 3071 (sstate.empty()) 3072 ) 3073 return; 3074 int iState = atoi(sstate.c_str()); 3075 3076 int urights = 3; 3077 bool bHaveUser = (session.username != ""); 3078 if (bHaveUser) 3079 { 3080 int iUser = FindUser(session.username.c_str()); 3081 if (iUser != -1) 3082 { 3083 urights = static_cast<int>(m_users[iUser].userrights); 3084 _log.Log(LOG_STATUS, "User: %s initiated a Thermostat State change command", m_users[iUser].Username.c_str()); 3085 } 3086 } 3087 if (urights < 1) 3088 return; 3089 3090 root["status"] = "OK"; 3091 root["title"] = "Set Thermostat State"; 3092 _log.Log(LOG_NORM, "Setting Thermostat State...."); 3093 m_mainworker.SetThermostatState(idx, iState); 3094 } 3095 Cmd_SystemShutdown(WebEmSession & session,const request & req,Json::Value & root)3096 void CWebServer::Cmd_SystemShutdown(WebEmSession & session, const request& req, Json::Value &root) 3097 { 3098 if (session.rights != 2) 3099 { 3100 session.reply_status = reply::forbidden; 3101 return; //Only admin user allowed 3102 } 3103 #ifdef WIN32 3104 int ret = system("shutdown -s -f -t 1 -d up:125:1"); 3105 #else 3106 int ret = system("sudo shutdown -h now"); 3107 #endif 3108 if (ret != 0) 3109 { 3110 _log.Log(LOG_ERROR, "Error executing shutdown command. returned: %d", ret); 3111 return; 3112 } 3113 root["title"] = "SystemShutdown"; 3114 root["status"] = "OK"; 3115 } 3116 Cmd_SystemReboot(WebEmSession & session,const request & req,Json::Value & root)3117 void CWebServer::Cmd_SystemReboot(WebEmSession & session, const request& req, Json::Value &root) 3118 { 3119 if (session.rights != 2) 3120 { 3121 session.reply_status = reply::forbidden; 3122 return; //Only admin user allowed 3123 } 3124 #ifdef WIN32 3125 int ret = system("shutdown -r -f -t 1 -d up:125:1"); 3126 #else 3127 int ret = system("sudo shutdown -r now"); 3128 #endif 3129 if (ret != 0) 3130 { 3131 _log.Log(LOG_ERROR, "Error executing reboot command. returned: %d", ret); 3132 return; 3133 } 3134 root["title"] = "SystemReboot"; 3135 root["status"] = "OK"; 3136 } 3137 Cmd_ExcecuteScript(WebEmSession & session,const request & req,Json::Value & root)3138 void CWebServer::Cmd_ExcecuteScript(WebEmSession & session, const request& req, Json::Value &root) 3139 { 3140 if (session.rights != 2) 3141 { 3142 session.reply_status = reply::forbidden; 3143 return; //Only admin user allowed 3144 } 3145 std::string scriptname = request::findValue(&req, "scriptname"); 3146 if (scriptname.empty()) 3147 return; 3148 if (scriptname.find("..") != std::string::npos) 3149 return; 3150 #ifdef WIN32 3151 scriptname = szUserDataFolder + "scripts\\" + scriptname; 3152 #else 3153 scriptname = szUserDataFolder + "scripts/" + scriptname; 3154 #endif 3155 if (!file_exist(scriptname.c_str())) 3156 return; 3157 std::string script_params = request::findValue(&req, "scriptparams"); 3158 std::string strparm = szUserDataFolder; 3159 if (!script_params.empty()) 3160 { 3161 if (strparm.size() > 0) 3162 strparm += " " + script_params; 3163 else 3164 strparm = script_params; 3165 } 3166 std::string sdirect = request::findValue(&req, "direct"); 3167 if (sdirect == "true") 3168 { 3169 _log.Log(LOG_STATUS, "Executing script: %s", scriptname.c_str()); 3170 #ifdef WIN32 3171 ShellExecute(NULL, "open", scriptname.c_str(), strparm.c_str(), NULL, SW_SHOWNORMAL); 3172 #else 3173 std::string lscript = scriptname + " " + strparm; 3174 int ret = system(lscript.c_str()); 3175 if (ret != 0) 3176 { 3177 _log.Log(LOG_ERROR, "Error executing script command (%s). returned: %d", lscript.c_str(), ret); 3178 return; 3179 } 3180 #endif 3181 } 3182 else 3183 { 3184 //add script to background worker 3185 m_sql.AddTaskItem(_tTaskItem::ExecuteScript(0.2f, scriptname, strparm)); 3186 } 3187 root["title"] = "ExecuteScript"; 3188 root["status"] = "OK"; 3189 } 3190 3191 //Only for Unix systems Cmd_UpdateApplication(WebEmSession & session,const request & req,Json::Value & root)3192 void CWebServer::Cmd_UpdateApplication(WebEmSession& session, const request& req, Json::Value& root) 3193 { 3194 if (session.rights != 2) 3195 { 3196 session.reply_status = reply::forbidden; 3197 return; //Only admin user allowed 3198 } 3199 #ifdef WIN32 3200 #ifndef _DEBUG 3201 return; 3202 #endif 3203 #endif 3204 int nValue; 3205 m_sql.GetPreferencesVar("ReleaseChannel", nValue); 3206 bool bIsBetaChannel = (nValue != 0); 3207 3208 std::string scriptname(szStartupFolder); 3209 scriptname += (bIsBetaChannel) ? "updatebeta" : "updaterelease"; 3210 //run script in background 3211 std::string lscript = scriptname + " &"; 3212 int ret = system(lscript.c_str()); 3213 root["title"] = "UpdateApplication"; 3214 root["status"] = "OK"; 3215 } 3216 Cmd_GetCosts(WebEmSession & session,const request & req,Json::Value & root)3217 void CWebServer::Cmd_GetCosts(WebEmSession & session, const request& req, Json::Value &root) 3218 { 3219 std::string idx = request::findValue(&req, "idx"); 3220 if (idx.empty()) 3221 return; 3222 char szTmp[100]; 3223 std::vector<std::vector<std::string> > result; 3224 result = m_sql.safe_query("SELECT Type, SubType, nValue, sValue FROM DeviceStatus WHERE (ID=='%q')", 3225 idx.c_str()); 3226 if (!result.empty()) 3227 { 3228 std::vector<std::string> sd = result[0]; 3229 3230 int nValue = 0; 3231 root["status"] = "OK"; 3232 root["title"] = "GetElectraCosts"; 3233 m_sql.GetPreferencesVar("CostEnergy", nValue); 3234 root["CostEnergy"] = nValue; 3235 m_sql.GetPreferencesVar("CostEnergyT2", nValue); 3236 root["CostEnergyT2"] = nValue; 3237 m_sql.GetPreferencesVar("CostEnergyR1", nValue); 3238 root["CostEnergyR1"] = nValue; 3239 m_sql.GetPreferencesVar("CostEnergyR2", nValue); 3240 root["CostEnergyR2"] = nValue; 3241 m_sql.GetPreferencesVar("CostGas", nValue); 3242 root["CostGas"] = nValue; 3243 m_sql.GetPreferencesVar("CostWater", nValue); 3244 root["CostWater"] = nValue; 3245 3246 int tValue = 1000; 3247 if (m_sql.GetPreferencesVar("MeterDividerWater", tValue)) 3248 { 3249 root["DividerWater"] = float(tValue); 3250 } 3251 3252 unsigned char dType = atoi(sd[0].c_str()); 3253 //unsigned char subType = atoi(sd[1].c_str()); 3254 //nValue = (unsigned char)atoi(sd[2].c_str()); 3255 std::string sValue = sd[3]; 3256 3257 if (dType == pTypeP1Power) 3258 { 3259 //also provide the counter values 3260 3261 std::vector<std::string> splitresults; 3262 StringSplit(sValue, ";", splitresults); 3263 if (splitresults.size() != 6) 3264 return; 3265 3266 float EnergyDivider = 1000.0f; 3267 if (m_sql.GetPreferencesVar("MeterDividerEnergy", tValue)) 3268 { 3269 EnergyDivider = float(tValue); 3270 } 3271 3272 unsigned long long powerusage1 = std::strtoull(splitresults[0].c_str(), nullptr, 10); 3273 unsigned long long powerusage2 = std::strtoull(splitresults[1].c_str(), nullptr, 10); 3274 unsigned long long powerdeliv1 = std::strtoull(splitresults[2].c_str(), nullptr, 10); 3275 unsigned long long powerdeliv2 = std::strtoull(splitresults[3].c_str(), nullptr, 10); 3276 //unsigned long long usagecurrent = std::strtoull(splitresults[4].c_str(), nullptr, 10); 3277 //unsigned long long delivcurrent = std::strtoull(splitresults[5].c_str(), nullptr, 10); 3278 3279 powerdeliv1 = (powerdeliv1 < 10) ? 0 : powerdeliv1; 3280 powerdeliv2 = (powerdeliv2 < 10) ? 0 : powerdeliv2; 3281 3282 sprintf(szTmp, "%.03f", float(powerusage1) / EnergyDivider); 3283 root["CounterT1"] = szTmp; 3284 sprintf(szTmp, "%.03f", float(powerusage2) / EnergyDivider); 3285 root["CounterT2"] = szTmp; 3286 sprintf(szTmp, "%.03f", float(powerdeliv1) / EnergyDivider); 3287 root["CounterR1"] = szTmp; 3288 sprintf(szTmp, "%.03f", float(powerdeliv2) / EnergyDivider); 3289 root["CounterR2"] = szTmp; 3290 } 3291 } 3292 } 3293 Cmd_CheckForUpdate(WebEmSession & session,const request & req,Json::Value & root)3294 void CWebServer::Cmd_CheckForUpdate(WebEmSession & session, const request& req, Json::Value &root) 3295 { 3296 bool bHaveUser = (session.username != ""); 3297 int urights = 3; 3298 if (bHaveUser) 3299 { 3300 int iUser = FindUser(session.username.c_str()); 3301 if (iUser != -1) 3302 urights = static_cast<int>(m_users[iUser].userrights); 3303 } 3304 root["statuscode"] = urights; 3305 3306 root["status"] = "OK"; 3307 root["title"] = "CheckForUpdate"; 3308 root["HaveUpdate"] = false; 3309 root["Revision"] = m_mainworker.m_iRevision; 3310 3311 if (session.rights != 2) 3312 { 3313 session.reply_status = reply::forbidden; 3314 return; //Only admin users may update 3315 } 3316 3317 bool bIsForced = (request::findValue(&req, "forced") == "true"); 3318 3319 if (!bIsForced) 3320 { 3321 int nValue = 0; 3322 m_sql.GetPreferencesVar("UseAutoUpdate", nValue); 3323 if (nValue != 1) 3324 { 3325 return; 3326 } 3327 } 3328 3329 root["HaveUpdate"] = m_mainworker.IsUpdateAvailable(bIsForced); 3330 root["DomoticzUpdateURL"] = m_mainworker.m_szDomoticzUpdateURL; 3331 root["SystemName"] = m_mainworker.m_szSystemName; 3332 root["Revision"] = m_mainworker.m_iRevision; 3333 } 3334 Cmd_DownloadUpdate(WebEmSession & session,const request & req,Json::Value & root)3335 void CWebServer::Cmd_DownloadUpdate(WebEmSession & session, const request& req, Json::Value &root) 3336 { 3337 if (!m_mainworker.StartDownloadUpdate()) 3338 return; 3339 root["status"] = "OK"; 3340 root["title"] = "DownloadUpdate"; 3341 } 3342 Cmd_DownloadReady(WebEmSession & session,const request & req,Json::Value & root)3343 void CWebServer::Cmd_DownloadReady(WebEmSession & session, const request& req, Json::Value &root) 3344 { 3345 if (!m_mainworker.m_bHaveDownloadedDomoticzUpdate) 3346 return; 3347 root["status"] = "OK"; 3348 root["title"] = "DownloadReady"; 3349 root["downloadok"] = (m_mainworker.m_bHaveDownloadedDomoticzUpdateSuccessFull) ? true : false; 3350 } 3351 Cmd_DeleteDatePoint(WebEmSession & session,const request & req,Json::Value & root)3352 void CWebServer::Cmd_DeleteDatePoint(WebEmSession & session, const request& req, Json::Value &root) 3353 { 3354 const std::string idx = request::findValue(&req, "idx"); 3355 const std::string Date = request::findValue(&req, "date"); 3356 if ( 3357 (idx.empty()) || 3358 (Date.empty()) 3359 ) 3360 return; 3361 root["status"] = "OK"; 3362 root["title"] = "deletedatapoint"; 3363 m_sql.DeleteDataPoint(idx.c_str(), Date); 3364 } 3365 IsIdxForUser(const WebEmSession * pSession,const int Idx)3366 bool CWebServer::IsIdxForUser(const WebEmSession *pSession, const int Idx) 3367 { 3368 if (pSession->rights == 2) 3369 return true; 3370 if (pSession->rights == 0) 3371 return false; //viewer 3372 //User 3373 int iUser = FindUser(pSession->username.c_str()); 3374 if ((iUser < 0) || (iUser >= (int)m_users.size())) 3375 return false; 3376 3377 if (m_users[iUser].TotSensors == 0) 3378 return true; // all sensors 3379 3380 std::vector<std::vector<std::string> > result = m_sql.safe_query("SELECT DeviceRowID FROM SharedDevices WHERE (SharedUserID == '%d') AND (DeviceRowID == '%d')", m_users[iUser].ID, Idx); 3381 return (!result.empty()); 3382 } 3383 3384 HandleCommand(const std::string & cparam,WebEmSession & session,const request & req,Json::Value & root)3385 void CWebServer::HandleCommand(const std::string &cparam, WebEmSession & session, const request& req, Json::Value &root) 3386 { 3387 std::map < std::string, webserver_response_function >::iterator pf = m_webcommands.find(cparam); 3388 if (pf != m_webcommands.end()) 3389 { 3390 pf->second(session, req, root); 3391 return; 3392 } 3393 3394 std::vector<std::vector<std::string> > result; 3395 char szTmp[300]; 3396 3397 bool bHaveUser = (session.username != ""); 3398 /* 3399 int iUser = -1; 3400 if (bHaveUser) 3401 { 3402 iUser = FindUser(session.username.c_str()); 3403 } 3404 */ 3405 if (cparam == "deleteallsubdevices") 3406 { 3407 if (session.rights < 2) 3408 { 3409 session.reply_status = reply::forbidden; 3410 return; //Only admin user allowed 3411 } 3412 3413 std::string idx = request::findValue(&req, "idx"); 3414 if (idx.empty()) 3415 return; 3416 root["status"] = "OK"; 3417 root["title"] = "DeleteAllSubDevices"; 3418 result = m_sql.safe_query("DELETE FROM LightSubDevices WHERE (ParentID == '%q')", idx.c_str()); 3419 } 3420 else if (cparam == "deletesubdevice") 3421 { 3422 if (session.rights < 2) 3423 { 3424 session.reply_status = reply::forbidden; 3425 return; //Only admin user allowed 3426 } 3427 3428 std::string idx = request::findValue(&req, "idx"); 3429 if (idx.empty()) 3430 return; 3431 root["status"] = "OK"; 3432 root["title"] = "DeleteSubDevice"; 3433 result = m_sql.safe_query("DELETE FROM LightSubDevices WHERE (ID == '%q')", idx.c_str()); 3434 } 3435 else if (cparam == "addsubdevice") 3436 { 3437 if (session.rights < 2) 3438 { 3439 session.reply_status = reply::forbidden; 3440 return; //Only admin user allowed 3441 } 3442 3443 std::string idx = request::findValue(&req, "idx"); 3444 std::string subidx = request::findValue(&req, "subidx"); 3445 if ((idx.empty()) || (subidx.empty())) 3446 return; 3447 if (idx == subidx) 3448 return; 3449 3450 //first check if it is not already a sub device 3451 result = m_sql.safe_query("SELECT ID FROM LightSubDevices WHERE (DeviceRowID=='%q') AND (ParentID =='%q')", 3452 subidx.c_str(), idx.c_str()); 3453 if (result.empty()) 3454 { 3455 root["status"] = "OK"; 3456 root["title"] = "AddSubDevice"; 3457 //no it is not, add it 3458 result = m_sql.safe_query( 3459 "INSERT INTO LightSubDevices (DeviceRowID, ParentID) VALUES ('%q','%q')", 3460 subidx.c_str(), 3461 idx.c_str() 3462 ); 3463 } 3464 } 3465 else if (cparam == "addscenedevice") 3466 { 3467 if (session.rights < 2) 3468 { 3469 session.reply_status = reply::forbidden; 3470 return; //Only admin user allowed 3471 } 3472 3473 std::string idx = request::findValue(&req, "idx"); 3474 std::string devidx = request::findValue(&req, "devidx"); 3475 std::string isscene = request::findValue(&req, "isscene"); 3476 std::string scommand = request::findValue(&req, "command"); 3477 int ondelay = atoi(request::findValue(&req, "ondelay").c_str()); 3478 int offdelay = atoi(request::findValue(&req, "offdelay").c_str()); 3479 3480 if ( 3481 (idx.empty()) || 3482 (devidx.empty()) || 3483 (isscene.empty()) 3484 ) 3485 return; 3486 int level = -1; 3487 if (request::hasValue(&req, "level")) 3488 level = atoi(request::findValue(&req, "level").c_str()); 3489 std::string color = _tColor(request::findValue(&req, "color")).toJSONString(); //Parse the color to detect incorrectly formatted color data 3490 3491 unsigned char command = 0; 3492 result = m_sql.safe_query("SELECT HardwareID, DeviceID, Unit, Type, SubType, SwitchType, Options FROM DeviceStatus WHERE (ID=='%q')", 3493 devidx.c_str()); 3494 if (!result.empty()) 3495 { 3496 int dType = atoi(result[0][3].c_str()); 3497 int sType = atoi(result[0][4].c_str()); 3498 _eSwitchType switchtype = (_eSwitchType)atoi(result[0][5].c_str()); 3499 std::map<std::string, std::string> options = m_sql.BuildDeviceOptions(result[0][6].c_str()); 3500 GetLightCommand(dType, sType, switchtype, scommand, command, options); 3501 } 3502 3503 //first check if this device is not the scene code! 3504 result = m_sql.safe_query("SELECT Activators, SceneType FROM Scenes WHERE (ID=='%q')", idx.c_str()); 3505 if (!result.empty()) 3506 { 3507 //int SceneType = atoi(result[0][1].c_str()); 3508 3509 std::vector<std::string> arrayActivators; 3510 StringSplit(result[0][0], ";", arrayActivators); 3511 for (const auto & ittAct : arrayActivators) 3512 { 3513 std::string sCodeCmd = ittAct; 3514 3515 std::vector<std::string> arrayCode; 3516 StringSplit(sCodeCmd, ":", arrayCode); 3517 3518 std::string sID = arrayCode[0]; 3519 std::string sCode = ""; 3520 if (arrayCode.size() == 2) 3521 { 3522 sCode = arrayCode[1]; 3523 } 3524 3525 if (sID == devidx) 3526 { 3527 return; //Group does not work with separate codes, so already there 3528 } 3529 } 3530 } 3531 //first check if it is not already a part of this scene/group (with the same OnDelay) 3532 if (isscene == "true") { 3533 result = m_sql.safe_query("SELECT ID FROM SceneDevices WHERE (DeviceRowID=='%q') AND (SceneRowID =='%q') AND (OnDelay == %d) AND (OffDelay == %d) AND (Cmd == %d)", 3534 devidx.c_str(), idx.c_str(), ondelay, offdelay, command); 3535 } 3536 else { 3537 result = m_sql.safe_query("SELECT ID FROM SceneDevices WHERE (DeviceRowID=='%q') AND (SceneRowID =='%q') AND (OnDelay == %d)", 3538 devidx.c_str(), idx.c_str(), ondelay); 3539 } 3540 if (result.empty()) 3541 { 3542 root["status"] = "OK"; 3543 root["title"] = "AddSceneDevice"; 3544 //no it is not, add it 3545 if (isscene == "true") 3546 { 3547 m_sql.safe_query( 3548 "INSERT INTO SceneDevices (DeviceRowID, SceneRowID, Cmd, Level, Color, OnDelay, OffDelay) VALUES ('%q','%q',%d,%d,'%q',%d,%d)", 3549 devidx.c_str(), 3550 idx.c_str(), 3551 command, 3552 level, 3553 color.c_str(), 3554 ondelay, 3555 offdelay 3556 ); 3557 } 3558 else 3559 { 3560 m_sql.safe_query( 3561 "INSERT INTO SceneDevices (DeviceRowID, SceneRowID, Level, Color, OnDelay, OffDelay) VALUES ('%q','%q',%d,'%q',%d,%d)", 3562 devidx.c_str(), 3563 idx.c_str(), 3564 level, 3565 color.c_str(), 3566 ondelay, 3567 offdelay 3568 ); 3569 } 3570 if (m_sql.m_bEnableEventSystem) 3571 m_mainworker.m_eventsystem.GetCurrentScenesGroups(); 3572 } 3573 } 3574 else if (cparam == "updatescenedevice") 3575 { 3576 if (session.rights < 2) 3577 { 3578 session.reply_status = reply::forbidden; 3579 return; //Only admin user allowed 3580 } 3581 3582 std::string idx = request::findValue(&req, "idx"); 3583 std::string devidx = request::findValue(&req, "devidx"); 3584 std::string scommand = request::findValue(&req, "command"); 3585 int ondelay = atoi(request::findValue(&req, "ondelay").c_str()); 3586 int offdelay = atoi(request::findValue(&req, "offdelay").c_str()); 3587 3588 if ( 3589 (idx.empty()) || 3590 (devidx.empty()) 3591 ) 3592 return; 3593 3594 unsigned char command = 0; 3595 3596 result = m_sql.safe_query("SELECT HardwareID, DeviceID, Unit, Type, SubType, SwitchType, Options FROM DeviceStatus WHERE (ID=='%q')", 3597 devidx.c_str()); 3598 if (!result.empty()) 3599 { 3600 int dType = atoi(result[0][3].c_str()); 3601 int sType = atoi(result[0][4].c_str()); 3602 _eSwitchType switchtype = (_eSwitchType)atoi(result[0][5].c_str()); 3603 std::map<std::string, std::string> options = m_sql.BuildDeviceOptions(result[0][6].c_str()); 3604 GetLightCommand(dType, sType, switchtype, scommand, command, options); 3605 } 3606 int level = -1; 3607 if (request::hasValue(&req, "level")) 3608 level = atoi(request::findValue(&req, "level").c_str()); 3609 std::string color = _tColor(request::findValue(&req, "color")).toJSONString(); //Parse the color to detect incorrectly formatted color data 3610 root["status"] = "OK"; 3611 root["title"] = "UpdateSceneDevice"; 3612 result = m_sql.safe_query( 3613 "UPDATE SceneDevices SET Cmd=%d, Level=%d, Color='%q', OnDelay=%d, OffDelay=%d WHERE (ID == '%q')", 3614 command, level, color.c_str(), ondelay, offdelay, idx.c_str()); 3615 } 3616 else if (cparam == "deletescenedevice") 3617 { 3618 if (session.rights < 2) 3619 { 3620 session.reply_status = reply::forbidden; 3621 return; //Only admin user allowed 3622 } 3623 3624 std::string idx = request::findValue(&req, "idx"); 3625 if (idx.empty()) 3626 return; 3627 root["status"] = "OK"; 3628 root["title"] = "DeleteSceneDevice"; 3629 m_sql.safe_query("DELETE FROM SceneDevices WHERE (ID == '%q')", idx.c_str()); 3630 m_sql.safe_query("DELETE FROM CamerasActiveDevices WHERE (DevSceneType==1) AND (DevSceneRowID == '%q')", idx.c_str()); 3631 if (m_sql.m_bEnableEventSystem) 3632 m_mainworker.m_eventsystem.GetCurrentScenesGroups(); 3633 } 3634 else if (cparam == "getsubdevices") 3635 { 3636 std::string idx = request::findValue(&req, "idx"); 3637 if (idx.empty()) 3638 return; 3639 3640 root["status"] = "OK"; 3641 root["title"] = "GetSubDevices"; 3642 result = m_sql.safe_query("SELECT a.ID, b.Name FROM LightSubDevices a, DeviceStatus b WHERE (a.ParentID=='%q') AND (b.ID == a.DeviceRowID)", 3643 idx.c_str()); 3644 if (!result.empty()) 3645 { 3646 int ii = 0; 3647 for (const auto & itt : result) 3648 { 3649 std::vector<std::string> sd = itt; 3650 3651 root["result"][ii]["ID"] = sd[0]; 3652 root["result"][ii]["Name"] = sd[1]; 3653 ii++; 3654 } 3655 } 3656 } 3657 else if (cparam == "getscenedevices") 3658 { 3659 std::string idx = request::findValue(&req, "idx"); 3660 std::string isscene = request::findValue(&req, "isscene"); 3661 3662 if ( 3663 (idx.empty()) || 3664 (isscene.empty()) 3665 ) 3666 return; 3667 3668 root["status"] = "OK"; 3669 root["title"] = "GetSceneDevices"; 3670 3671 result = m_sql.safe_query("SELECT a.ID, b.Name, a.DeviceRowID, b.Type, b.SubType, b.nValue, b.sValue, a.Cmd, a.Level, b.ID, a.[Order], a.Color, a.OnDelay, a.OffDelay, b.SwitchType FROM SceneDevices a, DeviceStatus b WHERE (a.SceneRowID=='%q') AND (b.ID == a.DeviceRowID) ORDER BY a.[Order]", 3672 idx.c_str()); 3673 if (!result.empty()) 3674 { 3675 int ii = 0; 3676 for (const auto & itt : result) 3677 { 3678 std::vector<std::string> sd = itt; 3679 3680 root["result"][ii]["ID"] = sd[0]; 3681 root["result"][ii]["Name"] = sd[1]; 3682 root["result"][ii]["DevID"] = sd[2]; 3683 root["result"][ii]["DevRealIdx"] = sd[9]; 3684 root["result"][ii]["Order"] = atoi(sd[10].c_str()); 3685 root["result"][ii]["OnDelay"] = atoi(sd[12].c_str()); 3686 root["result"][ii]["OffDelay"] = atoi(sd[13].c_str()); 3687 3688 _eSwitchType switchtype = (_eSwitchType)atoi(sd[14].c_str()); 3689 3690 unsigned char devType = atoi(sd[3].c_str()); 3691 3692 //switchtype seemed not to be used down with the GetLightStatus command, 3693 //causing RFY to go wrong, fixing here 3694 if (devType != pTypeRFY) 3695 switchtype = STYPE_OnOff; 3696 3697 unsigned char subType = atoi(sd[4].c_str()); 3698 //unsigned char nValue = (unsigned char)atoi(sd[5].c_str()); 3699 std::string sValue = sd[6]; 3700 int command = atoi(sd[7].c_str()); 3701 int level = atoi(sd[8].c_str()); 3702 3703 std::string lstatus = ""; 3704 int llevel = 0; 3705 bool bHaveDimmer = false; 3706 bool bHaveGroupCmd = false; 3707 int maxDimLevel = 0; 3708 GetLightStatus(devType, subType, switchtype, command, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd); 3709 root["result"][ii]["Command"] = lstatus; 3710 root["result"][ii]["Level"] = level; 3711 root["result"][ii]["Color"] = _tColor(sd[11]).toJSONString(); 3712 root["result"][ii]["Type"] = RFX_Type_Desc(devType, 1); 3713 root["result"][ii]["SubType"] = RFX_Type_SubType_Desc(devType, subType); 3714 ii++; 3715 } 3716 } 3717 } 3718 else if (cparam == "changescenedeviceorder") 3719 { 3720 if (session.rights < 2) 3721 { 3722 session.reply_status = reply::forbidden; 3723 return; //Only admin user allowed 3724 } 3725 3726 std::string idx = request::findValue(&req, "idx"); 3727 if (idx.empty()) 3728 return; 3729 std::string sway = request::findValue(&req, "way"); 3730 if (sway.empty()) 3731 return; 3732 bool bGoUp = (sway == "0"); 3733 3734 std::string aScene, aOrder, oID, oOrder; 3735 3736 //Get actual device order 3737 result = m_sql.safe_query("SELECT SceneRowID, [Order] FROM SceneDevices WHERE (ID=='%q')", 3738 idx.c_str()); 3739 if (result.empty()) 3740 return; 3741 aScene = result[0][0]; 3742 aOrder = result[0][1]; 3743 3744 if (!bGoUp) 3745 { 3746 //Get next device order 3747 result = m_sql.safe_query("SELECT ID, [Order] FROM SceneDevices WHERE (SceneRowID=='%q' AND [Order]>'%q') ORDER BY [Order] ASC", 3748 aScene.c_str(), aOrder.c_str()); 3749 if (result.empty()) 3750 return; 3751 oID = result[0][0]; 3752 oOrder = result[0][1]; 3753 } 3754 else 3755 { 3756 //Get previous device order 3757 result = m_sql.safe_query("SELECT ID, [Order] FROM SceneDevices WHERE (SceneRowID=='%q' AND [Order]<'%q') ORDER BY [Order] DESC", 3758 aScene.c_str(), aOrder.c_str()); 3759 if (result.empty()) 3760 return; 3761 oID = result[0][0]; 3762 oOrder = result[0][1]; 3763 } 3764 //Swap them 3765 root["status"] = "OK"; 3766 root["title"] = "ChangeSceneDeviceOrder"; 3767 3768 result = m_sql.safe_query("UPDATE SceneDevices SET [Order] = '%q' WHERE (ID='%q')", 3769 oOrder.c_str(), idx.c_str()); 3770 result = m_sql.safe_query("UPDATE SceneDevices SET [Order] = '%q' WHERE (ID='%q')", 3771 aOrder.c_str(), oID.c_str()); 3772 } 3773 else if (cparam == "deleteallscenedevices") 3774 { 3775 if (session.rights < 2) 3776 { 3777 session.reply_status = reply::forbidden; 3778 return; //Only admin user allowed 3779 } 3780 3781 std::string idx = request::findValue(&req, "idx"); 3782 if (idx.empty()) 3783 return; 3784 root["status"] = "OK"; 3785 root["title"] = "DeleteAllSceneDevices"; 3786 result = m_sql.safe_query("DELETE FROM SceneDevices WHERE (SceneRowID == %q)", idx.c_str()); 3787 } 3788 else if (cparam == "getmanualhardware") 3789 { 3790 //used by Add Manual Light/Switch dialog 3791 root["status"] = "OK"; 3792 root["title"] = "GetHardware"; 3793 result = m_sql.safe_query("SELECT ID, Name, Type FROM Hardware ORDER BY ID ASC"); 3794 if (!result.empty()) 3795 { 3796 int ii = 0; 3797 for (const auto & itt : result) 3798 { 3799 std::vector<std::string> sd = itt; 3800 3801 int ID = atoi(sd[0].c_str()); 3802 std::string Name = sd[1]; 3803 _eHardwareTypes Type = (_eHardwareTypes)atoi(sd[2].c_str()); 3804 3805 if ( 3806 (Type == HTYPE_RFXLAN) || 3807 (Type == HTYPE_RFXtrx315) || 3808 (Type == HTYPE_RFXtrx433) || 3809 (Type == HTYPE_RFXtrx868) || 3810 (Type == HTYPE_EnOceanESP2) || 3811 (Type == HTYPE_EnOceanESP3) || 3812 (Type == HTYPE_Dummy) || 3813 (Type == HTYPE_Tellstick) || 3814 (Type == HTYPE_EVOHOME_SCRIPT) || 3815 (Type == HTYPE_EVOHOME_SERIAL) || 3816 (Type == HTYPE_EVOHOME_WEB) || 3817 (Type == HTYPE_EVOHOME_TCP) || 3818 (Type == HTYPE_RaspberryGPIO) || 3819 (Type == HTYPE_RFLINKUSB) || 3820 (Type == HTYPE_RFLINKTCP) || 3821 (Type == HTYPE_ZIBLUEUSB) || 3822 (Type == HTYPE_ZIBLUETCP) || 3823 (Type == HTYPE_OpenWebNetTCP) || 3824 (Type == HTYPE_OpenWebNetUSB) || 3825 (Type == HTYPE_SysfsGpio) || 3826 (Type == HTYPE_USBtinGateway) 3827 ) 3828 { 3829 root["result"][ii]["idx"] = ID; 3830 root["result"][ii]["Name"] = Name; 3831 ii++; 3832 } 3833 } 3834 } 3835 } 3836 else if (cparam == "getgpio") 3837 { 3838 //used by Add Manual Light/Switch dialog 3839 root["title"] = "GetGpio"; 3840 #ifdef WITH_GPIO 3841 std::vector<CGpioPin> pins = CGpio::GetPinList(); 3842 if (pins.size() == 0) { 3843 root["status"] = "ERROR"; 3844 root["result"][0]["idx"] = 0; 3845 root["result"][0]["Name"] = "GPIO INIT ERROR"; 3846 } 3847 else { 3848 int ii = 0; 3849 for (const auto & it : pins) 3850 { 3851 CGpioPin pin = it; 3852 root["status"] = "OK"; 3853 root["result"][ii]["idx"] = pin.GetPin(); 3854 root["result"][ii]["Name"] = pin.ToString(); 3855 ii++; 3856 } 3857 } 3858 #else 3859 root["status"] = "OK"; 3860 root["result"][0]["idx"] = 0; 3861 root["result"][0]["Name"] = "N/A"; 3862 #endif 3863 } 3864 else if (cparam == "getsysfsgpio") 3865 { 3866 //used by Add Manual Light/Switch dialog 3867 root["title"] = "GetSysfsGpio"; 3868 #ifdef WITH_GPIO 3869 std::vector<int> gpio_ids = CSysfsGpio::GetGpioIds(); 3870 std::vector<std::string> gpio_names = CSysfsGpio::GetGpioNames(); 3871 3872 if (gpio_ids.size() == 0) { 3873 root["status"] = "ERROR"; 3874 root["result"][0]["idx"] = 0; 3875 root["result"][0]["Name"] = "No sysfs-gpio exports"; 3876 } 3877 else { 3878 for (int ii = 0; ii < gpio_ids.size(); ii++) 3879 { 3880 root["status"] = "OK"; 3881 root["result"][ii]["idx"] = gpio_ids[ii]; 3882 root["result"][ii]["Name"] = gpio_names[ii]; 3883 } 3884 } 3885 #else 3886 root["status"] = "OK"; 3887 root["result"][0]["idx"] = 0; 3888 root["result"][0]["Name"] = "N/A"; 3889 #endif 3890 } 3891 else if (cparam == "getlightswitches") 3892 { 3893 root["status"] = "OK"; 3894 root["title"] = "GetLightSwitches"; 3895 result = m_sql.safe_query("SELECT ID, Name, Type, SubType, Used, SwitchType, Options FROM DeviceStatus ORDER BY Name"); 3896 if (!result.empty()) 3897 { 3898 int ii = 0; 3899 for (const auto & itt : result) 3900 { 3901 std::vector<std::string> sd = itt; 3902 3903 std::string ID = sd[0]; 3904 std::string Name = sd[1]; 3905 int Type = atoi(sd[2].c_str()); 3906 int SubType = atoi(sd[3].c_str()); 3907 int used = atoi(sd[4].c_str()); 3908 _eSwitchType switchtype = (_eSwitchType)atoi(sd[5].c_str()); 3909 std::map<std::string, std::string> options = m_sql.BuildDeviceOptions(sd[6]); 3910 bool bdoAdd = false; 3911 switch (Type) 3912 { 3913 case pTypeLighting1: 3914 case pTypeLighting2: 3915 case pTypeLighting3: 3916 case pTypeLighting4: 3917 case pTypeLighting5: 3918 case pTypeLighting6: 3919 case pTypeFan: 3920 case pTypeColorSwitch: 3921 case pTypeSecurity1: 3922 case pTypeSecurity2: 3923 case pTypeEvohome: 3924 case pTypeEvohomeRelay: 3925 case pTypeCurtain: 3926 case pTypeBlinds: 3927 case pTypeRFY: 3928 case pTypeChime: 3929 case pTypeThermostat2: 3930 case pTypeThermostat3: 3931 case pTypeThermostat4: 3932 case pTypeRemote: 3933 case pTypeRadiator1: 3934 case pTypeGeneralSwitch: 3935 case pTypeHomeConfort: 3936 case pTypeFS20: 3937 case pTypeHunter: 3938 bdoAdd = true; 3939 if (!used) 3940 { 3941 bdoAdd = false; 3942 //bool bIsSubDevice = false; 3943 std::vector<std::vector<std::string> > resultSD; 3944 resultSD = m_sql.safe_query("SELECT ID FROM LightSubDevices WHERE (DeviceRowID=='%q')", 3945 sd[0].c_str()); 3946 if (resultSD.size() > 0) 3947 bdoAdd = true; 3948 } 3949 if ((Type == pTypeRadiator1) && (SubType != sTypeSmartwaresSwitchRadiator)) 3950 bdoAdd = false; 3951 if (bdoAdd) 3952 { 3953 int idx = atoi(ID.c_str()); 3954 if (!IsIdxForUser(&session, idx)) 3955 continue; 3956 root["result"][ii]["idx"] = ID; 3957 root["result"][ii]["Name"] = Name; 3958 root["result"][ii]["Type"] = RFX_Type_Desc(Type, 1); 3959 root["result"][ii]["SubType"] = RFX_Type_SubType_Desc(Type, SubType); 3960 bool bIsDimmer = ( 3961 (switchtype == STYPE_Dimmer) || 3962 (switchtype == STYPE_BlindsPercentage) || 3963 (switchtype == STYPE_BlindsPercentageInverted) || 3964 (switchtype == STYPE_Selector) 3965 ); 3966 root["result"][ii]["IsDimmer"] = bIsDimmer; 3967 3968 std::string dimmerLevels = "none"; 3969 3970 if (bIsDimmer) 3971 { 3972 std::stringstream ss; 3973 3974 if (switchtype == STYPE_Selector) { 3975 std::map<std::string, std::string> selectorStatuses; 3976 GetSelectorSwitchStatuses(options, selectorStatuses); 3977 bool levelOffHidden = (options["LevelOffHidden"] == "true"); 3978 for (int i = 0; i < (int)selectorStatuses.size(); i++) { 3979 if (levelOffHidden && (i == 0)) { 3980 continue; 3981 } 3982 if ((levelOffHidden && (i > 1)) || (i > 0)) { 3983 ss << ","; 3984 } 3985 ss << i * 10; 3986 } 3987 } 3988 else 3989 { 3990 int nValue = 0; 3991 std::string sValue = ""; 3992 std::string lstatus = ""; 3993 int llevel = 0; 3994 bool bHaveDimmer = false; 3995 int maxDimLevel = 0; 3996 bool bHaveGroupCmd = false; 3997 3998 GetLightStatus(Type, SubType, switchtype, nValue, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd); 3999 4000 for (int i = 0; i <= maxDimLevel; i++) 4001 { 4002 if (i != 0) 4003 { 4004 ss << ","; 4005 } 4006 ss << (int)float((100.0f / float(maxDimLevel))*i); 4007 } 4008 } 4009 dimmerLevels = ss.str(); 4010 } 4011 root["result"][ii]["DimmerLevels"] = dimmerLevels; 4012 ii++; 4013 } 4014 break; 4015 } 4016 } 4017 } 4018 } 4019 else if (cparam == "getlightswitchesscenes") 4020 { 4021 root["status"] = "OK"; 4022 root["title"] = "GetLightSwitchesScenes"; 4023 int ii = 0; 4024 4025 //First List/Switch Devices 4026 result = m_sql.safe_query("SELECT ID, Name, Type, SubType, Used FROM DeviceStatus ORDER BY Name"); 4027 if (!result.empty()) 4028 { 4029 for (const auto & itt : result) 4030 { 4031 std::vector<std::string> sd = itt; 4032 4033 std::string ID = sd[0]; 4034 std::string Name = sd[1]; 4035 int Type = atoi(sd[2].c_str()); 4036 int SubType = atoi(sd[3].c_str()); 4037 int used = atoi(sd[4].c_str()); 4038 if (used) 4039 { 4040 switch (Type) 4041 { 4042 case pTypeLighting1: 4043 case pTypeLighting2: 4044 case pTypeLighting3: 4045 case pTypeLighting4: 4046 case pTypeLighting5: 4047 case pTypeLighting6: 4048 case pTypeFan: 4049 case pTypeColorSwitch: 4050 case pTypeSecurity1: 4051 case pTypeSecurity2: 4052 case pTypeEvohome: 4053 case pTypeEvohomeRelay: 4054 case pTypeCurtain: 4055 case pTypeBlinds: 4056 case pTypeRFY: 4057 case pTypeChime: 4058 case pTypeThermostat2: 4059 case pTypeThermostat3: 4060 case pTypeThermostat4: 4061 case pTypeRemote: 4062 case pTypeGeneralSwitch: 4063 case pTypeHomeConfort: 4064 case pTypeFS20: 4065 case pTypeHunter: 4066 root["result"][ii]["type"] = 0; 4067 root["result"][ii]["idx"] = ID; 4068 root["result"][ii]["Name"] = "[Light/Switch] " + Name; 4069 ii++; 4070 break; 4071 case pTypeRadiator1: 4072 if (SubType == sTypeSmartwaresSwitchRadiator) 4073 { 4074 root["result"][ii]["type"] = 0; 4075 root["result"][ii]["idx"] = ID; 4076 root["result"][ii]["Name"] = "[Light/Switch] " + Name; 4077 ii++; 4078 } 4079 break; 4080 } 4081 } 4082 } 4083 }//end light/switches 4084 4085 //Add Scenes 4086 result = m_sql.safe_query("SELECT ID, Name FROM Scenes ORDER BY Name"); 4087 if (!result.empty()) 4088 { 4089 for (const auto & itt : result) 4090 { 4091 std::vector<std::string> sd = itt; 4092 4093 std::string ID = sd[0]; 4094 std::string Name = sd[1]; 4095 4096 root["result"][ii]["type"] = 1; 4097 root["result"][ii]["idx"] = ID; 4098 root["result"][ii]["Name"] = "[Scene] " + Name; 4099 ii++; 4100 } 4101 }//end light/switches 4102 } 4103 else if (cparam == "getcamactivedevices") 4104 { 4105 std::string idx = request::findValue(&req, "idx"); 4106 if (idx.empty()) 4107 return; 4108 root["status"] = "OK"; 4109 root["title"] = "GetCameraActiveDevices"; 4110 //First List/Switch Devices 4111 result = m_sql.safe_query("SELECT ID, DevSceneType, DevSceneRowID, DevSceneWhen, DevSceneDelay FROM CamerasActiveDevices WHERE (CameraRowID=='%q') ORDER BY ID", 4112 idx.c_str()); 4113 if (!result.empty()) 4114 { 4115 int ii = 0; 4116 for (const auto & itt : result) 4117 { 4118 std::vector<std::string> sd = itt; 4119 4120 std::string ID = sd[0]; 4121 int DevSceneType = atoi(sd[1].c_str()); 4122 std::string DevSceneRowID = sd[2]; 4123 int DevSceneWhen = atoi(sd[3].c_str()); 4124 int DevSceneDelay = atoi(sd[4].c_str()); 4125 4126 std::string Name = ""; 4127 if (DevSceneType == 0) 4128 { 4129 std::vector<std::vector<std::string> > result2; 4130 result2 = m_sql.safe_query("SELECT Name FROM DeviceStatus WHERE (ID=='%q')", 4131 DevSceneRowID.c_str()); 4132 if (!result2.empty()) 4133 { 4134 Name = "[Light/Switches] " + result2[0][0]; 4135 } 4136 } 4137 else 4138 { 4139 std::vector<std::vector<std::string> > result2; 4140 result2 = m_sql.safe_query("SELECT Name FROM Scenes WHERE (ID=='%q')", 4141 DevSceneRowID.c_str()); 4142 if (!result2.empty()) 4143 { 4144 Name = "[Scene] " + result2[0][0]; 4145 } 4146 } 4147 if (Name != "") 4148 { 4149 root["result"][ii]["idx"] = ID; 4150 root["result"][ii]["type"] = DevSceneType; 4151 root["result"][ii]["DevSceneRowID"] = DevSceneRowID; 4152 root["result"][ii]["when"] = DevSceneWhen; 4153 root["result"][ii]["delay"] = DevSceneDelay; 4154 root["result"][ii]["Name"] = Name; 4155 ii++; 4156 } 4157 } 4158 } 4159 } 4160 else if (cparam == "addcamactivedevice") 4161 { 4162 if (session.rights < 2) 4163 { 4164 session.reply_status = reply::forbidden; 4165 return; //Only admin user allowed 4166 } 4167 4168 std::string idx = request::findValue(&req, "idx"); 4169 std::string activeidx = request::findValue(&req, "activeidx"); 4170 std::string sactivetype = request::findValue(&req, "activetype"); 4171 std::string sactivewhen = request::findValue(&req, "activewhen"); 4172 std::string sactivedelay = request::findValue(&req, "activedelay"); 4173 4174 if ( 4175 (idx.empty()) || 4176 (activeidx.empty()) || 4177 (sactivetype.empty()) || 4178 (sactivewhen.empty()) || 4179 (sactivedelay.empty()) 4180 ) 4181 { 4182 return; 4183 } 4184 4185 int activetype = atoi(sactivetype.c_str()); 4186 int activewhen = atoi(sactivewhen.c_str()); 4187 int activedelay = atoi(sactivedelay.c_str()); 4188 4189 //first check if it is not already a Active Device 4190 result = m_sql.safe_query( 4191 "SELECT ID FROM CamerasActiveDevices WHERE (CameraRowID=='%q')" 4192 " AND (DevSceneType==%d) AND (DevSceneRowID=='%q')" 4193 " AND (DevSceneWhen==%d)", 4194 idx.c_str(), activetype, activeidx.c_str(), activewhen); 4195 if (result.empty()) 4196 { 4197 root["status"] = "OK"; 4198 root["title"] = "AddCameraActiveDevice"; 4199 //no it is not, add it 4200 result = m_sql.safe_query( 4201 "INSERT INTO CamerasActiveDevices (CameraRowID, DevSceneType, DevSceneRowID, DevSceneWhen, DevSceneDelay) VALUES ('%q',%d,'%q',%d,%d)", 4202 idx.c_str(), 4203 activetype, 4204 activeidx.c_str(), 4205 activewhen, 4206 activedelay 4207 ); 4208 m_mainworker.m_cameras.ReloadCameras(); 4209 } 4210 } 4211 else if (cparam == "deleteamactivedevice") 4212 { 4213 if (session.rights < 2) 4214 { 4215 session.reply_status = reply::forbidden; 4216 return; //Only admin user allowed 4217 } 4218 4219 std::string idx = request::findValue(&req, "idx"); 4220 if (idx.empty()) 4221 return; 4222 root["status"] = "OK"; 4223 root["title"] = "DeleteCameraActiveDevice"; 4224 result = m_sql.safe_query("DELETE FROM CamerasActiveDevices WHERE (ID == '%q')", idx.c_str()); 4225 m_mainworker.m_cameras.ReloadCameras(); 4226 } 4227 else if (cparam == "deleteallactivecamdevices") 4228 { 4229 if (session.rights < 2) 4230 { 4231 session.reply_status = reply::forbidden; 4232 return; //Only admin user allowed 4233 } 4234 4235 std::string idx = request::findValue(&req, "idx"); 4236 if (idx.empty()) 4237 return; 4238 root["status"] = "OK"; 4239 root["title"] = "DeleteAllCameraActiveDevices"; 4240 result = m_sql.safe_query("DELETE FROM CamerasActiveDevices WHERE (CameraRowID == '%q')", idx.c_str()); 4241 m_mainworker.m_cameras.ReloadCameras(); 4242 } 4243 else if (cparam == "testnotification") 4244 { 4245 if (session.rights < 2) 4246 { 4247 session.reply_status = reply::forbidden; 4248 return; //Only admin user allowed 4249 } 4250 4251 std::string notification_Title = "Domoticz test"; 4252 std::string notification_Message = "Domoticz test message!"; 4253 std::string subsystem = request::findValue(&req, "subsystem"); 4254 4255 std::string extraData = request::findValue(&req, "extradata"); 4256 4257 m_notifications.ConfigFromGetvars(req, false); 4258 if (m_notifications.SendMessage(0, std::string(""), subsystem, notification_Title, notification_Message, extraData, 1, std::string(""), false)) { 4259 root["status"] = "OK"; 4260 } 4261 /* we need to reload the config, because the values that were set were only for testing */ 4262 m_notifications.LoadConfig(); 4263 } 4264 else if (cparam == "testswitch") 4265 { 4266 std::string Username = "Admin"; 4267 if (!session.username.empty()) 4268 Username = session.username; 4269 if (session.rights < 2) 4270 { 4271 session.reply_status = reply::forbidden; 4272 return; //Only admin user allowed 4273 } 4274 4275 std::string hwdid = request::findValue(&req, "hwdid"); 4276 std::string sswitchtype = request::findValue(&req, "switchtype"); 4277 std::string slighttype = request::findValue(&req, "lighttype"); 4278 4279 if ( 4280 (hwdid.empty()) || 4281 (sswitchtype.empty()) || 4282 (slighttype.empty()) 4283 ) 4284 return; 4285 _eSwitchType switchtype = (_eSwitchType)atoi(sswitchtype.c_str()); 4286 int lighttype = atoi(slighttype.c_str()); 4287 int dtype; 4288 int subtype = 0; 4289 std::string sunitcode; 4290 std::string devid; 4291 4292 if (lighttype == 70) 4293 { 4294 //EnOcean (Lighting2 with Base_ID offset) 4295 dtype = pTypeLighting2; 4296 subtype = sTypeAC; 4297 std::string sgroupcode = request::findValue(&req, "groupcode"); 4298 sunitcode = request::findValue(&req, "unitcode"); 4299 int iUnitTest = atoi(sunitcode.c_str()); //only First Rocker_ID at the moment, gives us 128 devices we can control, should be enough! 4300 if ( 4301 (sunitcode.empty()) || 4302 (sgroupcode.empty()) || 4303 ((iUnitTest < 1) || (iUnitTest > 128)) 4304 ) 4305 return; 4306 sunitcode = sgroupcode;//Button A or B 4307 CDomoticzHardwareBase *pBaseHardware = reinterpret_cast<CDomoticzHardwareBase*>(m_mainworker.GetHardware(atoi(hwdid.c_str()))); 4308 if (pBaseHardware == NULL) 4309 return; 4310 if ((pBaseHardware->HwdType != HTYPE_EnOceanESP2) && (pBaseHardware->HwdType != HTYPE_EnOceanESP3) 4311 && (pBaseHardware->HwdType != HTYPE_USBtinGateway) ) 4312 return; 4313 unsigned long rID = 0; 4314 if (pBaseHardware->HwdType == HTYPE_EnOceanESP2) 4315 { 4316 CEnOceanESP2 *pEnoceanHardware = reinterpret_cast<CEnOceanESP2 *>(pBaseHardware); 4317 rID = pEnoceanHardware->m_id_base + iUnitTest; 4318 } 4319 else if (pBaseHardware->HwdType == HTYPE_EnOceanESP3) 4320 { 4321 CEnOceanESP3 *pEnoceanHardware = reinterpret_cast<CEnOceanESP3 *>(pBaseHardware); 4322 rID = pEnoceanHardware->m_id_base + iUnitTest; 4323 } 4324 else if (pBaseHardware->HwdType == HTYPE_USBtinGateway) //Like EnOcean (Lighting2 with Base_ID offset) 4325 { 4326 USBtin *pUSBtinHardware = reinterpret_cast<USBtin *>(pBaseHardware); 4327 //base ID calculate in the USBtinharwade dependant of the CAN Layer ! 4328 //for exemple see MultiblocV8 layer... 4329 rID = pUSBtinHardware->switch_id_base; 4330 std::stringstream ssunitcode; 4331 ssunitcode << iUnitTest; 4332 sunitcode = ssunitcode.str(); 4333 } 4334 //convert to hex, and we have our ID 4335 std::stringstream s_strid; 4336 s_strid << std::hex << std::uppercase << rID; 4337 devid = s_strid.str(); 4338 } 4339 else if (lighttype == 68) 4340 { 4341 #ifdef WITH_GPIO 4342 dtype = pTypeLighting1; 4343 subtype = sTypeIMPULS; 4344 devid = "0"; 4345 sunitcode = request::findValue(&req, "unitcode"); //Unit code = GPIO number 4346 4347 if (sunitcode.empty()) { 4348 root["status"] = "ERROR"; 4349 root["message"] = "No GPIO number given"; 4350 return; 4351 } 4352 CGpio *pGpio = reinterpret_cast<CGpio *>(m_mainworker.GetHardware(atoi(hwdid.c_str()))); 4353 if (pGpio == NULL) { 4354 root["status"] = "ERROR"; 4355 root["message"] = "Could not retrieve GPIO hardware pointer"; 4356 return; 4357 } 4358 if (pGpio->HwdType != HTYPE_RaspberryGPIO) { 4359 root["status"] = "ERROR"; 4360 root["message"] = "Given hardware is not GPIO"; 4361 return; 4362 } 4363 CGpioPin *pPin = CGpio::GetPPinById(atoi(sunitcode.c_str())); 4364 if (pPin == NULL) { 4365 root["status"] = "ERROR"; 4366 root["message"] = "Given pin does not exist on this GPIO hardware"; 4367 return; 4368 } 4369 if (pPin->GetIsInput()) { 4370 root["status"] = "ERROR"; 4371 root["message"] = "Given pin is not configured for output"; 4372 return; 4373 } 4374 #else 4375 root["status"] = "ERROR"; 4376 root["message"] = "GPIO support is disabled"; 4377 return; 4378 #endif 4379 } 4380 else if (lighttype == 69) 4381 { 4382 #ifdef WITH_GPIO 4383 4384 sunitcode = request::findValue(&req, "unitcode"); // sysfs-gpio number 4385 int unitcode = atoi(sunitcode.c_str()); 4386 dtype = pTypeLighting2; 4387 subtype = sTypeAC; 4388 std::string sswitchtype = request::findValue(&req, "switchtype"); 4389 _eSwitchType switchtype = (_eSwitchType)atoi(sswitchtype.c_str()); 4390 4391 std::string id = request::findValue(&req, "id"); 4392 if ((id.empty()) || (sunitcode.empty())) 4393 { 4394 return; 4395 } 4396 devid = id; 4397 4398 if (sunitcode.empty()) 4399 { 4400 root["status"] = "ERROR"; 4401 root["message"] = "No GPIO number given"; 4402 return; 4403 } 4404 4405 CSysfsGpio *pSysfsGpio = reinterpret_cast<CSysfsGpio *>(m_mainworker.GetHardware(atoi(hwdid.c_str()))); 4406 4407 if (pSysfsGpio == NULL) { 4408 root["status"] = "ERROR"; 4409 root["message"] = "Could not retrieve SysfsGpio hardware pointer"; 4410 return; 4411 } 4412 4413 if (pSysfsGpio->HwdType != HTYPE_SysfsGpio) { 4414 root["status"] = "ERROR"; 4415 root["message"] = "Given hardware is not SysfsGpio"; 4416 return; 4417 } 4418 #else 4419 root["status"] = "ERROR"; 4420 root["message"] = "GPIO support is disabled"; 4421 return; 4422 #endif 4423 } 4424 else if (lighttype < 20) 4425 { 4426 dtype = pTypeLighting1; 4427 subtype = lighttype; 4428 std::string shousecode = request::findValue(&req, "housecode"); 4429 sunitcode = request::findValue(&req, "unitcode"); 4430 if ( 4431 (shousecode.empty()) || 4432 (sunitcode.empty()) 4433 ) 4434 return; 4435 devid = shousecode; 4436 } 4437 else if (lighttype < 30) 4438 { 4439 dtype = pTypeLighting2; 4440 subtype = lighttype - 20; 4441 std::string id = request::findValue(&req, "id"); 4442 sunitcode = request::findValue(&req, "unitcode"); 4443 if ( 4444 (id.empty()) || 4445 (sunitcode.empty()) 4446 ) 4447 return; 4448 devid = id; 4449 } 4450 else if (lighttype < 70) 4451 { 4452 dtype = pTypeLighting5; 4453 subtype = lighttype - 50; 4454 if (lighttype == 59) 4455 subtype = sTypeIT; 4456 std::string id = request::findValue(&req, "id"); 4457 sunitcode = request::findValue(&req, "unitcode"); 4458 if ( 4459 (id.empty()) || 4460 (sunitcode.empty()) 4461 ) 4462 return; 4463 if ((subtype != sTypeEMW100) && (subtype != sTypeLivolo) && (subtype != sTypeLivolo1to10) && (subtype != sTypeRGB432W) && (subtype != sTypeIT)) 4464 devid = "00" + id; 4465 else 4466 devid = id; 4467 } 4468 else 4469 { 4470 if (lighttype == 100) 4471 { 4472 //Chime/ByronSX 4473 dtype = pTypeChime; 4474 subtype = sTypeByronSX; 4475 std::string id = request::findValue(&req, "id"); 4476 sunitcode = request::findValue(&req, "unitcode"); 4477 if ( 4478 (id.empty()) || 4479 (sunitcode.empty()) 4480 ) 4481 return; 4482 int iUnitCode = atoi(sunitcode.c_str()) - 1; 4483 switch (iUnitCode) 4484 { 4485 case 0: 4486 iUnitCode = chime_sound0; 4487 break; 4488 case 1: 4489 iUnitCode = chime_sound1; 4490 break; 4491 case 2: 4492 iUnitCode = chime_sound2; 4493 break; 4494 case 3: 4495 iUnitCode = chime_sound3; 4496 break; 4497 case 4: 4498 iUnitCode = chime_sound4; 4499 break; 4500 case 5: 4501 iUnitCode = chime_sound5; 4502 break; 4503 case 6: 4504 iUnitCode = chime_sound6; 4505 break; 4506 case 7: 4507 iUnitCode = chime_sound7; 4508 break; 4509 } 4510 sprintf(szTmp, "%d", iUnitCode); 4511 sunitcode = szTmp; 4512 devid = id; 4513 } 4514 else if (lighttype == 101) 4515 { 4516 //Curtain Harrison 4517 dtype = pTypeCurtain; 4518 subtype = sTypeHarrison; 4519 std::string shousecode = request::findValue(&req, "housecode"); 4520 sunitcode = request::findValue(&req, "unitcode"); 4521 if ( 4522 (shousecode.empty()) || 4523 (sunitcode.empty()) 4524 ) 4525 return; 4526 devid = shousecode; 4527 } 4528 else if (lighttype == 102) 4529 { 4530 //RFY 4531 dtype = pTypeRFY; 4532 subtype = sTypeRFY; 4533 std::string id = request::findValue(&req, "id"); 4534 sunitcode = request::findValue(&req, "unitcode"); 4535 if ( 4536 (id.empty()) || 4537 (sunitcode.empty()) 4538 ) 4539 return; 4540 devid = id; 4541 } 4542 else if (lighttype == 103) 4543 { 4544 //Meiantech 4545 dtype = pTypeSecurity1; 4546 subtype = sTypeMeiantech; 4547 std::string id = request::findValue(&req, "id"); 4548 if ( 4549 (id.empty()) 4550 ) 4551 return; 4552 devid = id; 4553 sunitcode = "0"; 4554 } 4555 else if (lighttype == 104) 4556 { 4557 //HE105 4558 dtype = pTypeThermostat2; 4559 subtype = sTypeHE105; 4560 sunitcode = request::findValue(&req, "unitcode"); 4561 if (sunitcode.empty()) 4562 return; 4563 //convert to hex, and we have our Unit Code 4564 std::stringstream s_strid; 4565 s_strid << std::hex << std::uppercase << sunitcode; 4566 int iUnitCode; 4567 s_strid >> iUnitCode; 4568 sprintf(szTmp, "%d", iUnitCode); 4569 sunitcode = szTmp; 4570 devid = "1"; 4571 } 4572 else if (lighttype == 105) 4573 { 4574 //ASA 4575 dtype = pTypeRFY; 4576 subtype = sTypeASA; 4577 std::string id = request::findValue(&req, "id"); 4578 sunitcode = request::findValue(&req, "unitcode"); 4579 if ( 4580 (id.empty()) || 4581 (sunitcode.empty()) 4582 ) 4583 return; 4584 devid = id; 4585 } 4586 else if (lighttype == 106) 4587 { 4588 //Blyss 4589 dtype = pTypeLighting6; 4590 subtype = sTypeBlyss; 4591 std::string sgroupcode = request::findValue(&req, "groupcode"); 4592 sunitcode = request::findValue(&req, "unitcode"); 4593 std::string id = request::findValue(&req, "id"); 4594 if ( 4595 (sgroupcode.empty()) || 4596 (sunitcode.empty()) || 4597 (id.empty()) 4598 ) 4599 return; 4600 devid = id + sgroupcode; 4601 } 4602 else if (lighttype == 107) 4603 { 4604 //RFY2 4605 dtype = pTypeRFY; 4606 subtype = sTypeRFY2; 4607 std::string id = request::findValue(&req, "id"); 4608 sunitcode = request::findValue(&req, "unitcode"); 4609 if ( 4610 (id.empty()) || 4611 (sunitcode.empty()) 4612 ) 4613 return; 4614 devid = id; 4615 } 4616 else if ((lighttype >= 200) && (lighttype < 300)) 4617 { 4618 dtype = pTypeBlinds; 4619 subtype = lighttype - 200; 4620 std::string id = request::findValue(&req, "id"); 4621 sunitcode = request::findValue(&req, "unitcode"); 4622 if ( 4623 (id.empty()) || 4624 (sunitcode.empty()) 4625 ) 4626 return; 4627 int iUnitCode = atoi(sunitcode.c_str()); 4628 sprintf(szTmp, "%d", iUnitCode); 4629 sunitcode = szTmp; 4630 devid = id; 4631 } 4632 else if (lighttype == 301) 4633 { 4634 //Smartwares Radiator 4635 dtype = pTypeRadiator1; 4636 subtype = sTypeSmartwaresSwitchRadiator; 4637 std::string id = request::findValue(&req, "id"); 4638 sunitcode = request::findValue(&req, "unitcode"); 4639 if ( 4640 (id.empty()) || 4641 (sunitcode.empty()) 4642 ) 4643 return; 4644 devid = id; 4645 } 4646 else if (lighttype == 302) 4647 { 4648 //Home Confort 4649 dtype = pTypeHomeConfort; 4650 subtype = sTypeHomeConfortTEL010; 4651 std::string id = request::findValue(&req, "id"); 4652 4653 std::string shousecode = request::findValue(&req, "housecode"); 4654 sunitcode = request::findValue(&req, "unitcode"); 4655 if ( 4656 (id.empty()) || 4657 (shousecode.empty()) || 4658 (sunitcode.empty()) 4659 ) 4660 return; 4661 4662 int iUnitCode = atoi(sunitcode.c_str()); 4663 sprintf(szTmp, "%d", iUnitCode); 4664 sunitcode = szTmp; 4665 sprintf(szTmp, "%02X", atoi(shousecode.c_str())); 4666 shousecode = szTmp; 4667 devid = id + shousecode; 4668 } 4669 else if (lighttype == 303) 4670 { 4671 //Selector Switch 4672 dtype = pTypeGeneralSwitch; 4673 subtype = sSwitchTypeSelector; 4674 std::string id = request::findValue(&req, "id"); 4675 sunitcode = request::findValue(&req, "unitcode"); 4676 if ( 4677 (id.empty()) || 4678 (sunitcode.empty()) 4679 ) 4680 return; 4681 devid = id; 4682 } 4683 else if (lighttype == 304) 4684 { 4685 //Itho CVE RFT 4686 dtype = pTypeFan; 4687 subtype = sTypeItho; 4688 std::string id = request::findValue(&req, "id"); 4689 if (id.empty()) 4690 return; 4691 devid = id; 4692 sunitcode = "0"; 4693 } 4694 else if (lighttype == 305) 4695 { 4696 //Lucci Air/DC 4697 dtype = pTypeFan; 4698 subtype = sTypeLucciAir; 4699 std::string id = request::findValue(&req, "id"); 4700 if (id.empty()) 4701 return; 4702 devid = id; 4703 sunitcode = "0"; 4704 } 4705 else if (lighttype == 306) 4706 { 4707 //Lucci Air DC 4708 dtype = pTypeFan; 4709 subtype = sTypeLucciAirDC; 4710 std::string id = request::findValue(&req, "id"); 4711 if (id.empty()) 4712 return; 4713 devid = id; 4714 sunitcode = "0"; 4715 } 4716 else if (lighttype == 307) 4717 { 4718 //Westinghouse 4719 dtype = pTypeFan; 4720 subtype = sTypeWestinghouse; 4721 std::string id = request::findValue(&req, "id"); 4722 if (id.empty()) 4723 return; 4724 devid = id; 4725 sunitcode = "0"; 4726 } 4727 else if (lighttype == 400) { 4728 //Openwebnet Bus Blinds 4729 dtype = pTypeGeneralSwitch; 4730 subtype = sSwitchTypeAC; 4731 devid = request::findValue(&req, "id"); 4732 sunitcode = request::findValue(&req, "unitcode"); 4733 if ( 4734 (devid.empty()) || 4735 (sunitcode.empty()) 4736 ) 4737 return; 4738 } 4739 else if (lighttype == 401) { 4740 //Openwebnet Bus Lights 4741 dtype = pTypeGeneralSwitch; 4742 subtype = sSwitchTypeAC; 4743 devid = request::findValue(&req, "id"); 4744 sunitcode = request::findValue(&req, "unitcode"); 4745 if ( 4746 (devid.empty()) || 4747 (sunitcode.empty()) 4748 ) 4749 return; 4750 } 4751 else if (lighttype == 402) 4752 { 4753 //Openwebnet Bus Auxiliary 4754 dtype = pTypeGeneralSwitch; 4755 subtype = sSwitchTypeAC; 4756 devid = request::findValue(&req, "id"); 4757 sunitcode = request::findValue(&req, "unitcode"); 4758 if ( 4759 (devid.empty()) || 4760 (sunitcode.empty()) 4761 ) 4762 return; 4763 } 4764 else if (lighttype == 403) { 4765 //Openwebnet Zigbee Blinds 4766 dtype = pTypeGeneralSwitch; 4767 subtype = sSwitchBlindsT2; 4768 devid = request::findValue(&req, "id"); 4769 sunitcode = request::findValue(&req, "unitcode"); 4770 if ( 4771 (devid.empty()) || 4772 (sunitcode.empty()) 4773 ) 4774 return; 4775 } 4776 else if (lighttype == 404) { 4777 //Light Openwebnet Zigbee 4778 dtype = pTypeGeneralSwitch; 4779 subtype = sSwitchLightT2; 4780 devid = request::findValue(&req, "id"); 4781 sunitcode = request::findValue(&req, "unitcode"); 4782 if ( 4783 (devid.empty()) || 4784 (sunitcode.empty()) 4785 ) 4786 return; 4787 } 4788 else if ((lighttype == 405) || (lighttype == 406)) { 4789 // Openwebnet Dry Contact / IR Detection 4790 dtype = pTypeGeneralSwitch; 4791 subtype = sSwitchContactT1; 4792 devid = request::findValue(&req, "id"); 4793 sunitcode = request::findValue(&req, "unitcode"); 4794 if ( 4795 (devid.empty()) || 4796 (sunitcode.empty()) 4797 ) 4798 return; 4799 } 4800 else if (lighttype == 407) { 4801 //Openwebnet Bus Custom 4802 dtype = pTypeGeneralSwitch; 4803 subtype = sSwitchTypeAC; 4804 devid = request::findValue(&req, "id"); 4805 sunitcode = request::findValue(&req, "unitcode"); 4806 std::string StrParam1 = request::findValue(&req, "StrParam1"); 4807 if ( 4808 (devid.empty()) || 4809 (sunitcode.empty()) || 4810 (StrParam1.empty()) 4811 ) 4812 { 4813 root["message"] = "Some field empty or not valid."; 4814 return; 4815 } 4816 } 4817 } 4818 // ----------- If needed convert to GeneralSwitch type (for o.a. RFlink) ----------- 4819 CDomoticzHardwareBase *pBaseHardware = reinterpret_cast<CDomoticzHardwareBase*>(m_mainworker.GetHardware(atoi(hwdid.c_str()))); 4820 if (pBaseHardware != NULL) 4821 { 4822 if ((pBaseHardware->HwdType == HTYPE_RFLINKUSB) || (pBaseHardware->HwdType == HTYPE_RFLINKTCP)) { 4823 ConvertToGeneralSwitchType(devid, dtype, subtype); 4824 } 4825 } 4826 // ----------------------------------------------- 4827 4828 root["status"] = "OK"; 4829 root["message"] = "OK"; 4830 root["title"] = "TestSwitch"; 4831 std::vector<std::string> sd; 4832 4833 sd.push_back(hwdid); 4834 sd.push_back(devid); 4835 sd.push_back(sunitcode); 4836 sprintf(szTmp, "%d", dtype); 4837 sd.push_back(szTmp); 4838 sprintf(szTmp, "%d", subtype); 4839 sd.push_back(szTmp); 4840 sprintf(szTmp, "%d", switchtype); 4841 sd.push_back(szTmp); 4842 sd.push_back(""); //AddjValue2 4843 sd.push_back(""); //nValue 4844 sd.push_back(""); //sValue 4845 sd.push_back(""); //Name 4846 sd.push_back(""); //Options 4847 4848 std::string switchcmd = "On"; 4849 int level = 0; 4850 if (lighttype == 70) 4851 { 4852 //Special EnOcean case, if it is a dimmer, set a dim value 4853 if (switchtype == STYPE_Dimmer) 4854 level = 5; 4855 } 4856 m_mainworker.SwitchLightInt(sd, switchcmd, level, NoColor, true, Username); 4857 } 4858 else if (cparam == "addswitch") 4859 { 4860 if (session.rights < 2) 4861 { 4862 session.reply_status = reply::forbidden; 4863 return; //Only admin user allowed 4864 } 4865 4866 std::string hwdid = request::findValue(&req, "hwdid"); 4867 std::string name = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 4868 std::string sswitchtype = request::findValue(&req, "switchtype"); 4869 std::string slighttype = request::findValue(&req, "lighttype"); 4870 std::string maindeviceidx = request::findValue(&req, "maindeviceidx"); 4871 std::string deviceoptions; 4872 4873 if ( 4874 (hwdid.empty()) || 4875 (sswitchtype.empty()) || 4876 (slighttype.empty()) || 4877 (name.empty()) 4878 ) 4879 return; 4880 _eSwitchType switchtype = (_eSwitchType)atoi(sswitchtype.c_str()); 4881 int lighttype = atoi(slighttype.c_str()); 4882 int dtype = 0; 4883 int subtype = 0; 4884 std::string sunitcode; 4885 std::string devid; 4886 std::string StrParam1; 4887 4888 #ifdef ENABLE_PYTHON 4889 //check if HW is plugin 4890 { 4891 result = m_sql.safe_query("SELECT Type FROM Hardware WHERE (ID == '%q')", hwdid.c_str()); 4892 if (!result.empty()) 4893 { 4894 std::vector<std::string> sd = result[0]; 4895 _eHardwareTypes Type = (_eHardwareTypes)atoi(sd[0].c_str()); 4896 if (Type == HTYPE_PythonPlugin) 4897 { 4898 // Not allowed to add device to plugin HW (plugin framework does not use key column "ID" but instead uses column "unit" as key) 4899 _log.Log(LOG_ERROR, "CWebServer::HandleCommand addswitch: Not allowed to add device owned by plugin %u!", atoi(hwdid.c_str())); 4900 root["message"] = "Not allowed to add switch to plugin HW!"; 4901 return; 4902 } 4903 } 4904 } 4905 #endif 4906 4907 if (lighttype == 70) 4908 { 4909 //EnOcean (Lighting2 with Base_ID offset) 4910 dtype = pTypeLighting2; 4911 subtype = sTypeAC; 4912 sunitcode = request::findValue(&req, "unitcode"); 4913 std::string sgroupcode = request::findValue(&req, "groupcode"); 4914 int iUnitTest = atoi(sunitcode.c_str()); //gives us 128 devices we can control, should be enough! 4915 if ( 4916 (sunitcode.empty()) || 4917 (sgroupcode.empty()) || 4918 ((iUnitTest < 1) || (iUnitTest > 128)) 4919 ) 4920 return; 4921 sunitcode = sgroupcode;//Button A/B 4922 CDomoticzHardwareBase *pBaseHardware = reinterpret_cast<CDomoticzHardwareBase*>(m_mainworker.GetHardware(atoi(hwdid.c_str()))); 4923 if (pBaseHardware == NULL) 4924 return; 4925 if ((pBaseHardware->HwdType != HTYPE_EnOceanESP2) && (pBaseHardware->HwdType != HTYPE_EnOceanESP3) 4926 && (pBaseHardware->HwdType != HTYPE_USBtinGateway) ) 4927 return; 4928 unsigned long rID = 0; 4929 if (pBaseHardware->HwdType == HTYPE_EnOceanESP2) 4930 { 4931 CEnOceanESP2 *pEnoceanHardware = reinterpret_cast<CEnOceanESP2*>(pBaseHardware); 4932 if (pEnoceanHardware->m_id_base == 0) 4933 { 4934 root["message"] = "BaseID not found, is the hardware running?"; 4935 return; 4936 } 4937 rID = pEnoceanHardware->m_id_base + iUnitTest; 4938 } 4939 else if (pBaseHardware->HwdType == HTYPE_EnOceanESP3) 4940 { 4941 CEnOceanESP3 *pEnoceanHardware = reinterpret_cast<CEnOceanESP3*>(pBaseHardware); 4942 if (pEnoceanHardware->m_id_base == 0) 4943 { 4944 root["message"] = "BaseID not found, is the hardware running?"; 4945 return; 4946 } 4947 rID = pEnoceanHardware->m_id_base + iUnitTest; 4948 } 4949 else if (pBaseHardware->HwdType == HTYPE_USBtinGateway) 4950 { 4951 USBtin *pUSBtinHardware = reinterpret_cast<USBtin *>(pBaseHardware); 4952 rID = pUSBtinHardware->switch_id_base; 4953 std::stringstream ssunitcode; 4954 ssunitcode << iUnitTest; 4955 sunitcode = ssunitcode.str(); 4956 } 4957 //convert to hex, and we have our ID 4958 std::stringstream s_strid; 4959 s_strid << std::hex << std::uppercase << rID; 4960 devid = s_strid.str(); 4961 } 4962 else if (lighttype == 68) 4963 { 4964 #ifdef WITH_GPIO 4965 dtype = pTypeLighting1; 4966 subtype = sTypeIMPULS; 4967 devid = "0"; 4968 sunitcode = request::findValue(&req, "unitcode"); //Unit code = GPIO number 4969 4970 if (sunitcode.empty()) { 4971 return; 4972 } 4973 CGpio *pGpio = reinterpret_cast<CGpio *>(m_mainworker.GetHardware(atoi(hwdid.c_str()))); 4974 if (pGpio == NULL) { 4975 return; 4976 } 4977 if (pGpio->HwdType != HTYPE_RaspberryGPIO) { 4978 return; 4979 } 4980 CGpioPin *pPin = CGpio::GetPPinById(atoi(sunitcode.c_str())); 4981 if (pPin == NULL) { 4982 return; 4983 } 4984 #else 4985 return; 4986 #endif 4987 } 4988 else if (lighttype == 69) 4989 { 4990 #ifdef WITH_GPIO 4991 dtype = pTypeLighting2; 4992 subtype = sTypeAC; 4993 devid = "0"; 4994 sunitcode = request::findValue(&req, "unitcode"); // sysfs-gpio number 4995 int unitcode = atoi(sunitcode.c_str()); 4996 std::string sswitchtype = request::findValue(&req, "switchtype"); 4997 _eSwitchType switchtype = (_eSwitchType)atoi(sswitchtype.c_str()); 4998 std::string id = request::findValue(&req, "id"); 4999 CSysfsGpio::RequestDbUpdate(unitcode); 5000 5001 if ((id.empty()) || (sunitcode.empty())) 5002 { 5003 return; 5004 } 5005 devid = id; 5006 5007 CSysfsGpio *pSysfsGpio = reinterpret_cast<CSysfsGpio *>(m_mainworker.GetHardware(atoi(hwdid.c_str()))); 5008 5009 if ((pSysfsGpio == NULL) || (pSysfsGpio->HwdType != HTYPE_SysfsGpio)) 5010 { 5011 return; 5012 } 5013 #else 5014 return; 5015 #endif 5016 } 5017 else if (lighttype < 20) 5018 { 5019 dtype = pTypeLighting1; 5020 subtype = lighttype; 5021 std::string shousecode = request::findValue(&req, "housecode"); 5022 sunitcode = request::findValue(&req, "unitcode"); 5023 if ( 5024 (shousecode.empty()) || 5025 (sunitcode.empty()) 5026 ) 5027 return; 5028 devid = shousecode; 5029 } 5030 else if (lighttype < 30) 5031 { 5032 dtype = pTypeLighting2; 5033 subtype = lighttype - 20; 5034 std::string id = request::findValue(&req, "id"); 5035 sunitcode = request::findValue(&req, "unitcode"); 5036 if ( 5037 (id.empty()) || 5038 (sunitcode.empty()) 5039 ) 5040 return; 5041 devid = id; 5042 } 5043 else if (lighttype < 70) 5044 { 5045 dtype = pTypeLighting5; 5046 subtype = lighttype - 50; 5047 if (lighttype == 59) 5048 subtype = sTypeIT; 5049 std::string id = request::findValue(&req, "id"); 5050 sunitcode = request::findValue(&req, "unitcode"); 5051 if ( 5052 (id.empty()) || 5053 (sunitcode.empty()) 5054 ) 5055 return; 5056 if ((subtype != sTypeEMW100) && (subtype != sTypeLivolo) && (subtype != sTypeLivolo1to10) && (subtype != sTypeRGB432W) && (subtype != sTypeLightwaveRF) && (subtype != sTypeIT)) 5057 devid = "00" + id; 5058 else 5059 devid = id; 5060 } 5061 else if (lighttype == 101) 5062 { 5063 //Curtain Harrison 5064 dtype = pTypeCurtain; 5065 subtype = sTypeHarrison; 5066 std::string shousecode = request::findValue(&req, "housecode"); 5067 sunitcode = request::findValue(&req, "unitcode"); 5068 if ( 5069 (shousecode.empty()) || 5070 (sunitcode.empty()) 5071 ) 5072 return; 5073 devid = shousecode; 5074 } 5075 else if (lighttype == 102) 5076 { 5077 //RFY 5078 dtype = pTypeRFY; 5079 subtype = sTypeRFY; 5080 std::string id = request::findValue(&req, "id"); 5081 sunitcode = request::findValue(&req, "unitcode"); 5082 if ( 5083 (id.empty()) || 5084 (sunitcode.empty()) 5085 ) 5086 return; 5087 devid = id; 5088 } 5089 else if (lighttype == 103) 5090 { 5091 //Meiantech 5092 dtype = pTypeSecurity1; 5093 subtype = sTypeMeiantech; 5094 std::string id = request::findValue(&req, "id"); 5095 if ( 5096 (id.empty()) 5097 ) 5098 return; 5099 devid = id; 5100 sunitcode = "0"; 5101 } 5102 else if (lighttype == 104) 5103 { 5104 //HE105 5105 dtype = pTypeThermostat2; 5106 subtype = sTypeHE105; 5107 sunitcode = request::findValue(&req, "unitcode"); 5108 if (sunitcode.empty()) 5109 return; 5110 //convert to hex, and we have our Unit Code 5111 std::stringstream s_strid; 5112 s_strid << std::hex << std::uppercase << sunitcode; 5113 int iUnitCode; 5114 s_strid >> iUnitCode; 5115 sprintf(szTmp, "%d", iUnitCode); 5116 sunitcode = szTmp; 5117 devid = "1"; 5118 } 5119 else if (lighttype == 105) 5120 { 5121 //ASA 5122 dtype = pTypeRFY; 5123 subtype = sTypeASA; 5124 std::string id = request::findValue(&req, "id"); 5125 sunitcode = request::findValue(&req, "unitcode"); 5126 if ( 5127 (id.empty()) || 5128 (sunitcode.empty()) 5129 ) 5130 return; 5131 devid = id; 5132 } 5133 else if (lighttype == 106) 5134 { 5135 //Blyss 5136 dtype = pTypeLighting6; 5137 subtype = sTypeBlyss; 5138 std::string sgroupcode = request::findValue(&req, "groupcode"); 5139 sunitcode = request::findValue(&req, "unitcode"); 5140 std::string id = request::findValue(&req, "id"); 5141 if ( 5142 (sgroupcode.empty()) || 5143 (sunitcode.empty()) || 5144 (id.empty()) 5145 ) 5146 return; 5147 devid = id + sgroupcode; 5148 } 5149 else if (lighttype == 107) 5150 { 5151 //RFY2 5152 dtype = pTypeRFY; 5153 subtype = sTypeRFY2; 5154 std::string id = request::findValue(&req, "id"); 5155 sunitcode = request::findValue(&req, "unitcode"); 5156 if ( 5157 (id.empty()) || 5158 (sunitcode.empty()) 5159 ) 5160 return; 5161 devid = id; 5162 } 5163 else 5164 { 5165 if (lighttype == 100) 5166 { 5167 //Chime/ByronSX 5168 dtype = pTypeChime; 5169 subtype = sTypeByronSX; 5170 std::string id = request::findValue(&req, "id"); 5171 sunitcode = request::findValue(&req, "unitcode"); 5172 if ( 5173 (id.empty()) || 5174 (sunitcode.empty()) 5175 ) 5176 return; 5177 int iUnitCode = atoi(sunitcode.c_str()) - 1; 5178 switch (iUnitCode) 5179 { 5180 case 0: 5181 iUnitCode = chime_sound0; 5182 break; 5183 case 1: 5184 iUnitCode = chime_sound1; 5185 break; 5186 case 2: 5187 iUnitCode = chime_sound2; 5188 break; 5189 case 3: 5190 iUnitCode = chime_sound3; 5191 break; 5192 case 4: 5193 iUnitCode = chime_sound4; 5194 break; 5195 case 5: 5196 iUnitCode = chime_sound5; 5197 break; 5198 case 6: 5199 iUnitCode = chime_sound6; 5200 break; 5201 case 7: 5202 iUnitCode = chime_sound7; 5203 break; 5204 } 5205 sprintf(szTmp, "%d", iUnitCode); 5206 sunitcode = szTmp; 5207 devid = id; 5208 } 5209 else if ((lighttype >= 200) && (lighttype < 300)) 5210 { 5211 dtype = pTypeBlinds; 5212 subtype = lighttype - 200; 5213 std::string id = request::findValue(&req, "id"); 5214 sunitcode = request::findValue(&req, "unitcode"); 5215 if ( 5216 (id.empty()) || 5217 (sunitcode.empty()) 5218 ) 5219 return; 5220 int iUnitCode = atoi(sunitcode.c_str()); 5221 sprintf(szTmp, "%d", iUnitCode); 5222 sunitcode = szTmp; 5223 devid = id; 5224 } 5225 else if (lighttype == 301) 5226 { 5227 //Smartwares Radiator 5228 std::string id = request::findValue(&req, "id"); 5229 sunitcode = request::findValue(&req, "unitcode"); 5230 if ( 5231 (id.empty()) || 5232 (sunitcode.empty()) 5233 ) 5234 return; 5235 devid = id; 5236 5237 //For this device, we will also need to add a Radiator type, do that first 5238 dtype = pTypeRadiator1; 5239 subtype = sTypeSmartwares; 5240 5241 //check if switch is unique 5242 result = m_sql.safe_query( 5243 "SELECT Name FROM DeviceStatus WHERE (HardwareID=='%q' AND DeviceID=='%q' AND Unit=='%q' AND Type==%d AND SubType==%d)", 5244 hwdid.c_str(), devid.c_str(), sunitcode.c_str(), dtype, subtype); 5245 if (!result.empty()) 5246 { 5247 root["message"] = "Switch already exists!"; 5248 return; 5249 } 5250 bool bActEnabledState = m_sql.m_bAcceptNewHardware; 5251 m_sql.m_bAcceptNewHardware = true; 5252 std::string devname; 5253 m_sql.UpdateValue(atoi(hwdid.c_str()), devid.c_str(), atoi(sunitcode.c_str()), dtype, subtype, 0, -1, 0, "20.5", devname); 5254 m_sql.m_bAcceptNewHardware = bActEnabledState; 5255 5256 //set name and switchtype 5257 result = m_sql.safe_query( 5258 "SELECT ID FROM DeviceStatus WHERE (HardwareID=='%q' AND DeviceID=='%q' AND Unit=='%q' AND Type==%d AND SubType==%d)", 5259 hwdid.c_str(), devid.c_str(), sunitcode.c_str(), dtype, subtype); 5260 if (result.empty()) 5261 { 5262 root["message"] = "Error finding switch in Database!?!?"; 5263 return; 5264 } 5265 std::string ID = result[0][0]; 5266 5267 m_sql.safe_query( 5268 "UPDATE DeviceStatus SET Used=1, Name='%q', SwitchType=%d WHERE (ID == '%q')", 5269 name.c_str(), switchtype, ID.c_str()); 5270 5271 //Now continue to insert the switch 5272 dtype = pTypeRadiator1; 5273 subtype = sTypeSmartwaresSwitchRadiator; 5274 } 5275 else if (lighttype == 302) 5276 { 5277 //Home Confort 5278 dtype = pTypeHomeConfort; 5279 subtype = sTypeHomeConfortTEL010; 5280 std::string id = request::findValue(&req, "id"); 5281 5282 std::string shousecode = request::findValue(&req, "housecode"); 5283 sunitcode = request::findValue(&req, "unitcode"); 5284 if ( 5285 (id.empty()) || 5286 (shousecode.empty()) || 5287 (sunitcode.empty()) 5288 ) 5289 return; 5290 5291 int iUnitCode = atoi(sunitcode.c_str()); 5292 sprintf(szTmp, "%d", iUnitCode); 5293 sunitcode = szTmp; 5294 sprintf(szTmp, "%02X", atoi(shousecode.c_str())); 5295 shousecode = szTmp; 5296 devid = id + shousecode; 5297 } 5298 else if (lighttype == 303) 5299 { 5300 //Selector Switch 5301 dtype = pTypeGeneralSwitch; 5302 subtype = sSwitchTypeSelector; 5303 std::string id = request::findValue(&req, "id"); 5304 sunitcode = request::findValue(&req, "unitcode"); 5305 if ( 5306 (id.empty()) || 5307 (sunitcode.empty()) 5308 ) 5309 return; 5310 devid = "0" + id; 5311 switchtype = STYPE_Selector; 5312 if (!deviceoptions.empty()) { 5313 deviceoptions.append(";"); 5314 } 5315 deviceoptions.append("SelectorStyle:0;LevelNames:Off|Level1|Level2|Level3"); 5316 } 5317 else if (lighttype == 304) 5318 { 5319 //Itho CVE RFT 5320 dtype = pTypeFan; 5321 subtype = sTypeItho; 5322 std::string id = request::findValue(&req, "id"); 5323 if (id.empty()) 5324 return; 5325 devid = id; 5326 sunitcode = "0"; 5327 } 5328 else if (lighttype == 305) 5329 { 5330 //Lucci Air 5331 dtype = pTypeFan; 5332 subtype = sTypeLucciAir; 5333 std::string id = request::findValue(&req, "id"); 5334 if (id.empty()) 5335 return; 5336 devid = id; 5337 sunitcode = "0"; 5338 } 5339 else if (lighttype == 306) 5340 { 5341 //Lucci Air DC 5342 dtype = pTypeFan; 5343 subtype = sTypeLucciAirDC; 5344 std::string id = request::findValue(&req, "id"); 5345 if (id.empty()) 5346 return; 5347 devid = id; 5348 sunitcode = "0"; 5349 } 5350 else if (lighttype == 307) 5351 { 5352 //Westinghouse 5353 dtype = pTypeFan; 5354 subtype = sTypeWestinghouse; 5355 std::string id = request::findValue(&req, "id"); 5356 if (id.empty()) 5357 return; 5358 devid = id; 5359 sunitcode = "0"; 5360 } 5361 else if (lighttype == 400) 5362 { 5363 //Openwebnet Bus Blinds 5364 dtype = pTypeGeneralSwitch; 5365 subtype = sSwitchTypeAC; 5366 devid = request::findValue(&req, "id"); 5367 sunitcode = request::findValue(&req, "unitcode"); 5368 if ( 5369 (devid.empty()) || 5370 (sunitcode.empty()) 5371 ) 5372 return; 5373 } 5374 else if (lighttype == 401) 5375 { 5376 //Openwebnet Bus Lights 5377 dtype = pTypeGeneralSwitch; 5378 subtype = sSwitchTypeAC; 5379 devid = request::findValue(&req, "id"); 5380 sunitcode = request::findValue(&req, "unitcode"); 5381 if ( 5382 (devid.empty()) || 5383 (sunitcode.empty()) 5384 ) 5385 return; 5386 } 5387 else if (lighttype == 402) 5388 { 5389 //Openwebnet Bus Auxiliary 5390 dtype = pTypeGeneralSwitch; 5391 subtype = sSwitchTypeAC; 5392 devid = request::findValue(&req, "id"); 5393 sunitcode = request::findValue(&req, "unitcode"); 5394 if ( 5395 (devid.empty()) || 5396 (sunitcode.empty()) 5397 ) 5398 return; 5399 } 5400 else if (lighttype == 403) 5401 { 5402 //Openwebnet Zigbee Blinds 5403 dtype = pTypeGeneralSwitch; 5404 subtype = sSwitchBlindsT2; 5405 devid = request::findValue(&req, "id"); 5406 sunitcode = request::findValue(&req, "unitcode"); 5407 if ( 5408 (devid.empty()) || 5409 (sunitcode.empty()) 5410 ) 5411 return; 5412 } 5413 else if (lighttype == 404) 5414 { 5415 //Openwebnet Zigbee Lights 5416 dtype = pTypeGeneralSwitch; 5417 subtype = sSwitchLightT2; 5418 devid = request::findValue(&req, "id"); 5419 sunitcode = request::findValue(&req, "unitcode"); 5420 if ( 5421 (devid.empty()) || 5422 (sunitcode.empty()) 5423 ) 5424 return; 5425 } 5426 else if ((lighttype == 405) || (lighttype == 406)) 5427 { 5428 //Openwebnet Dry Contact / IR Detection 5429 dtype = pTypeGeneralSwitch; 5430 subtype = sSwitchContactT1; 5431 devid = request::findValue(&req, "id"); 5432 sunitcode = request::findValue(&req, "unitcode"); 5433 if ( 5434 (devid.empty()) || 5435 (sunitcode.empty()) 5436 ) 5437 return; 5438 } 5439 else if (lighttype == 407) { 5440 //Openwebnet Bus Custom 5441 dtype = pTypeGeneralSwitch; 5442 subtype = sSwitchTypeAC; 5443 devid = request::findValue(&req, "id"); 5444 sunitcode = request::findValue(&req, "unitcode"); 5445 StrParam1 = request::findValue(&req, "StrParam1"); 5446 _log.Log(LOG_STATUS, "COpenWebNetTCP: custom command: '%s'", StrParam1.c_str()); 5447 if ( 5448 (devid.empty()) || 5449 (sunitcode.empty()) || 5450 (StrParam1.empty()) 5451 ) 5452 { 5453 root["message"] = "Some field empty or not valid."; 5454 return; 5455 } 5456 } 5457 } 5458 5459 //check if switch is unique 5460 result = m_sql.safe_query( 5461 "SELECT Name FROM DeviceStatus WHERE (HardwareID=='%q' AND DeviceID=='%q' AND Unit=='%q' AND Type==%d AND SubType==%d)", 5462 hwdid.c_str(), devid.c_str(), sunitcode.c_str(), dtype, subtype); 5463 if (!result.empty()) 5464 { 5465 root["message"] = "Switch already exists!"; 5466 return; 5467 } 5468 5469 // ----------- If needed convert to GeneralSwitch type (for o.a. RFlink) ----------- 5470 CDomoticzHardwareBase *pBaseHardware = m_mainworker.GetHardware(atoi(hwdid.c_str())); 5471 if (pBaseHardware != NULL) 5472 { 5473 if ((pBaseHardware->HwdType == HTYPE_RFLINKUSB) || (pBaseHardware->HwdType == HTYPE_RFLINKTCP)) { 5474 ConvertToGeneralSwitchType(devid, dtype, subtype); 5475 } 5476 } 5477 // ----------------------------------------------- 5478 5479 bool bActEnabledState = m_sql.m_bAcceptNewHardware; 5480 m_sql.m_bAcceptNewHardware = true; 5481 std::string devname; 5482 m_sql.UpdateValue(atoi(hwdid.c_str()), devid.c_str(), atoi(sunitcode.c_str()), dtype, subtype, 0, -1, 0, devname); 5483 m_sql.m_bAcceptNewHardware = bActEnabledState; 5484 5485 //set name and switchtype 5486 result = m_sql.safe_query( 5487 "SELECT ID FROM DeviceStatus WHERE (HardwareID=='%q' AND DeviceID=='%q' AND Unit=='%q' AND Type==%d AND SubType==%d)", 5488 hwdid.c_str(), devid.c_str(), sunitcode.c_str(), dtype, subtype); 5489 if (result.empty()) 5490 { 5491 root["message"] = "Error finding switch in Database!?!?"; 5492 return; 5493 } 5494 std::string ID = result[0][0]; 5495 5496 m_sql.safe_query( 5497 "UPDATE DeviceStatus SET Used=1, Name='%q', SwitchType=%d WHERE (ID == '%q')", 5498 name.c_str(), switchtype, ID.c_str()); 5499 5500 if (lighttype == 407) { 5501 //Openwebnet Bus Custom 5502 m_sql.safe_query( 5503 "UPDATE DeviceStatus SET StrParam1='%s' WHERE (ID == '%q')", 5504 StrParam1.c_str(), ID.c_str()); 5505 } 5506 5507 m_mainworker.m_eventsystem.GetCurrentStates(); 5508 5509 //Set device options 5510 m_sql.SetDeviceOptions(atoi(ID.c_str()), m_sql.BuildDeviceOptions(deviceoptions, false)); 5511 5512 if (maindeviceidx != "") 5513 { 5514 if (maindeviceidx != ID) 5515 { 5516 //this is a sub device for another light/switch 5517 //first check if it is not already a sub device 5518 result = m_sql.safe_query( 5519 "SELECT ID FROM LightSubDevices WHERE (DeviceRowID=='%q') AND (ParentID =='%q')", 5520 ID.c_str(), maindeviceidx.c_str()); 5521 if (result.empty()) 5522 { 5523 //no it is not, add it 5524 result = m_sql.safe_query( 5525 "INSERT INTO LightSubDevices (DeviceRowID, ParentID) VALUES ('%q','%q')", 5526 ID.c_str(), 5527 maindeviceidx.c_str() 5528 ); 5529 } 5530 } 5531 } 5532 5533 root["status"] = "OK"; 5534 root["title"] = "AddSwitch"; 5535 } 5536 else if (cparam == "getnotificationtypes") 5537 { 5538 if (session.rights < 2) 5539 { 5540 session.reply_status = reply::forbidden; 5541 return; //Only admin user allowed 5542 } 5543 5544 std::string idx = request::findValue(&req, "idx"); 5545 if (idx.empty()) 5546 return; 5547 //First get Device Type/SubType 5548 result = m_sql.safe_query("SELECT Type, SubType, SwitchType FROM DeviceStatus WHERE (ID == '%q')", 5549 idx.c_str()); 5550 if (result.empty()) 5551 return; 5552 5553 root["status"] = "OK"; 5554 root["title"] = "GetNotificationTypes"; 5555 unsigned char dType = atoi(result[0][0].c_str()); 5556 unsigned char dSubType = atoi(result[0][1].c_str()); 5557 unsigned char switchtype = atoi(result[0][2].c_str()); 5558 5559 int ii = 0; 5560 if ( 5561 (dType == pTypeLighting1) || 5562 (dType == pTypeLighting2) || 5563 (dType == pTypeLighting3) || 5564 (dType == pTypeLighting4) || 5565 (dType == pTypeLighting5) || 5566 (dType == pTypeLighting6) || 5567 (dType == pTypeColorSwitch) || 5568 (dType == pTypeSecurity1) || 5569 (dType == pTypeSecurity2) || 5570 (dType == pTypeEvohome) || 5571 (dType == pTypeEvohomeRelay) || 5572 (dType == pTypeCurtain) || 5573 (dType == pTypeBlinds) || 5574 (dType == pTypeRFY) || 5575 (dType == pTypeChime) || 5576 (dType == pTypeThermostat2) || 5577 (dType == pTypeThermostat3) || 5578 (dType == pTypeThermostat4) || 5579 (dType == pTypeRemote) || 5580 (dType == pTypeGeneralSwitch) || 5581 (dType == pTypeHomeConfort) || 5582 (dType == pTypeFS20) || 5583 ((dType == pTypeRadiator1) && (dSubType == sTypeSmartwaresSwitchRadiator)) 5584 ) 5585 { 5586 if (switchtype != STYPE_PushOff) 5587 { 5588 root["result"][ii]["val"] = NTYPE_SWITCH_ON; 5589 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_SWITCH_ON, 0); 5590 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_SWITCH_ON, 1); 5591 ii++; 5592 } 5593 if (switchtype != STYPE_PushOn) 5594 { 5595 root["result"][ii]["val"] = NTYPE_SWITCH_OFF; 5596 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_SWITCH_OFF, 0); 5597 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_SWITCH_OFF, 1); 5598 ii++; 5599 } 5600 if (switchtype == STYPE_Media) 5601 { 5602 std::string idx = request::findValue(&req, "idx"); 5603 5604 result = m_sql.safe_query("SELECT HardwareID FROM DeviceStatus WHERE (ID=='%q')", idx.c_str()); 5605 if (!result.empty()) 5606 { 5607 std::string hdwid = result[0][0]; 5608 CDomoticzHardwareBase *pBaseHardware = reinterpret_cast<CDomoticzHardwareBase*>(m_mainworker.GetHardware(atoi(hdwid.c_str()))); 5609 if (pBaseHardware != NULL) { 5610 _eHardwareTypes type = pBaseHardware->HwdType; 5611 root["result"][ii]["val"] = NTYPE_PAUSED; 5612 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_PAUSED, 0); 5613 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_PAUSED, 1); 5614 ii++; 5615 if (type == HTYPE_Kodi) { 5616 root["result"][ii]["val"] = NTYPE_AUDIO; 5617 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_AUDIO, 0); 5618 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_AUDIO, 1); 5619 ii++; 5620 root["result"][ii]["val"] = NTYPE_VIDEO; 5621 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_VIDEO, 0); 5622 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_VIDEO, 1); 5623 ii++; 5624 root["result"][ii]["val"] = NTYPE_PHOTO; 5625 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_PHOTO, 0); 5626 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_PHOTO, 1); 5627 ii++; 5628 } 5629 if (type == HTYPE_LogitechMediaServer) { 5630 root["result"][ii]["val"] = NTYPE_PLAYING; 5631 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_PLAYING, 0); 5632 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_PLAYING, 1); 5633 ii++; 5634 root["result"][ii]["val"] = NTYPE_STOPPED; 5635 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_STOPPED, 0); 5636 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_STOPPED, 1); 5637 ii++; 5638 } 5639 if (type == HTYPE_HEOS) { 5640 root["result"][ii]["val"] = NTYPE_PLAYING; 5641 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_PLAYING, 0); 5642 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_PLAYING, 1); 5643 ii++; 5644 root["result"][ii]["val"] = NTYPE_STOPPED; 5645 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_STOPPED, 0); 5646 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_STOPPED, 1); 5647 ii++; 5648 } 5649 } 5650 } 5651 } 5652 } 5653 if ( 5654 ( 5655 (dType == pTypeTEMP) || 5656 (dType == pTypeTEMP_HUM) || 5657 (dType == pTypeTEMP_HUM_BARO) || 5658 (dType == pTypeTEMP_BARO) || 5659 (dType == pTypeEvohomeZone) || 5660 (dType == pTypeEvohomeWater) || 5661 (dType == pTypeThermostat1) || 5662 (dType == pTypeRego6XXTemp) || 5663 ((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorTemp)) 5664 ) || 5665 ((dType == pTypeUV) && (dSubType == sTypeUV3)) || 5666 ((dType == pTypeWIND) && (dSubType == sTypeWIND4)) || 5667 ((dType == pTypeWIND) && (dSubType == sTypeWINDNoTemp)) || 5668 ((dType == pTypeGeneral) && (dSubType == sTypeSystemTemp)) 5669 ) 5670 { 5671 root["result"][ii]["val"] = NTYPE_TEMPERATURE; 5672 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_TEMPERATURE, 0); 5673 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_TEMPERATURE, 1); 5674 ii++; 5675 } 5676 if ( 5677 (dType == pTypeHUM) || 5678 (dType == pTypeTEMP_HUM) || 5679 (dType == pTypeTEMP_HUM_BARO) 5680 ) 5681 { 5682 root["result"][ii]["val"] = NTYPE_HUMIDITY; 5683 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_HUMIDITY, 0); 5684 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_HUMIDITY, 1); 5685 ii++; 5686 } 5687 if ( 5688 (dType == pTypeTEMP_HUM) || 5689 (dType == pTypeTEMP_HUM_BARO) 5690 ) 5691 { 5692 root["result"][ii]["val"] = NTYPE_DEWPOINT; 5693 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_DEWPOINT, 0); 5694 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_DEWPOINT, 1); 5695 ii++; 5696 } 5697 if (dType == pTypeRAIN) 5698 { 5699 root["result"][ii]["val"] = NTYPE_RAIN; 5700 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_RAIN, 0); 5701 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_RAIN, 1); 5702 ii++; 5703 } 5704 if (dType == pTypeWIND) 5705 { 5706 root["result"][ii]["val"] = NTYPE_WIND; 5707 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_WIND, 0); 5708 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_WIND, 1); 5709 ii++; 5710 } 5711 if (dType == pTypeUV) 5712 { 5713 root["result"][ii]["val"] = NTYPE_UV; 5714 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_UV, 0); 5715 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_UV, 1); 5716 ii++; 5717 } 5718 if ( 5719 (dType == pTypeTEMP_HUM_BARO) || 5720 (dType == pTypeBARO) || 5721 (dType == pTypeTEMP_BARO) 5722 ) 5723 { 5724 root["result"][ii]["val"] = NTYPE_BARO; 5725 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_BARO, 0); 5726 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_BARO, 1); 5727 ii++; 5728 } 5729 if ( 5730 ((dType == pTypeRFXMeter) && (dSubType == sTypeRFXMeterCount)) || 5731 ((dType == pTypeGeneral) && (dSubType == sTypeCounterIncremental)) || 5732 (dType == pTypeYouLess) || 5733 ((dType == pTypeRego6XXValue) && (dSubType == sTypeRego6XXCounter)) 5734 ) 5735 { 5736 if ((switchtype == MTYPE_ENERGY) || (switchtype == MTYPE_ENERGY_GENERATED)) 5737 { 5738 root["result"][ii]["val"] = NTYPE_TODAYENERGY; 5739 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_TODAYENERGY, 0); 5740 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_TODAYENERGY, 1); 5741 } 5742 else if (switchtype == MTYPE_GAS) 5743 { 5744 root["result"][ii]["val"] = NTYPE_TODAYGAS; 5745 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_TODAYGAS, 0); 5746 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_TODAYGAS, 1); 5747 } 5748 else if (switchtype == MTYPE_COUNTER) 5749 { 5750 root["result"][ii]["val"] = NTYPE_TODAYCOUNTER; 5751 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_TODAYCOUNTER, 0); 5752 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_TODAYCOUNTER, 1); 5753 } 5754 else 5755 { 5756 //water (same as gas) 5757 root["result"][ii]["val"] = NTYPE_TODAYGAS; 5758 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_TODAYGAS, 0); 5759 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_TODAYGAS, 1); 5760 } 5761 ii++; 5762 } 5763 if (dType == pTypeYouLess) 5764 { 5765 root["result"][ii]["val"] = NTYPE_USAGE; 5766 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5767 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5768 ii++; 5769 } 5770 if (dType == pTypeAirQuality) 5771 { 5772 root["result"][ii]["val"] = NTYPE_USAGE; 5773 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5774 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5775 ii++; 5776 } 5777 else if ((dType == pTypeGeneral) && ((dSubType == sTypeSoilMoisture) || (dSubType == sTypeLeafWetness))) 5778 { 5779 root["result"][ii]["val"] = NTYPE_USAGE; 5780 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5781 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5782 ii++; 5783 } 5784 if ((dType == pTypeGeneral) && (dSubType == sTypeVisibility)) 5785 { 5786 root["result"][ii]["val"] = NTYPE_USAGE; 5787 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5788 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5789 ii++; 5790 } 5791 if ((dType == pTypeGeneral) && (dSubType == sTypeDistance)) 5792 { 5793 root["result"][ii]["val"] = NTYPE_USAGE; 5794 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5795 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5796 ii++; 5797 } 5798 if ((dType == pTypeGeneral) && (dSubType == sTypeSolarRadiation)) 5799 { 5800 root["result"][ii]["val"] = NTYPE_USAGE; 5801 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5802 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5803 ii++; 5804 } 5805 if ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) 5806 { 5807 root["result"][ii]["val"] = NTYPE_USAGE; 5808 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5809 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5810 ii++; 5811 } 5812 if ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) 5813 { 5814 root["result"][ii]["val"] = NTYPE_USAGE; 5815 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5816 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5817 ii++; 5818 } 5819 if ((dType == pTypeGeneral) && (dSubType == sTypePressure)) 5820 { 5821 root["result"][ii]["val"] = NTYPE_USAGE; 5822 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5823 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5824 ii++; 5825 } 5826 if ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 5827 { 5828 root["result"][ii]["val"] = NTYPE_USAGE; 5829 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5830 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5831 ii++; 5832 } 5833 if (dType == pTypeLux) 5834 { 5835 root["result"][ii]["val"] = NTYPE_USAGE; 5836 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5837 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5838 ii++; 5839 } 5840 if ((dType == pTypeGeneral) && (dSubType == sTypeSoundLevel)) 5841 { 5842 root["result"][ii]["val"] = NTYPE_USAGE; 5843 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5844 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5845 ii++; 5846 } 5847 if (dType == pTypeWEIGHT) 5848 { 5849 root["result"][ii]["val"] = NTYPE_USAGE; 5850 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5851 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5852 ii++; 5853 } 5854 if (dType == pTypeUsage) 5855 { 5856 root["result"][ii]["val"] = NTYPE_USAGE; 5857 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5858 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5859 ii++; 5860 } 5861 if ( 5862 (dType == pTypeENERGY) || 5863 ((dType == pTypeGeneral) && (dSubType == sTypeKwh)) 5864 ) 5865 { 5866 root["result"][ii]["val"] = NTYPE_USAGE; 5867 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5868 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5869 ii++; 5870 } 5871 if (dType == pTypePOWER) 5872 { 5873 root["result"][ii]["val"] = NTYPE_USAGE; 5874 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5875 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5876 ii++; 5877 } 5878 if ((dType == pTypeCURRENT) && (dSubType == sTypeELEC1)) 5879 { 5880 root["result"][ii]["val"] = NTYPE_AMPERE1; 5881 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_AMPERE1, 0); 5882 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_AMPERE1, 1); 5883 ii++; 5884 root["result"][ii]["val"] = NTYPE_AMPERE2; 5885 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_AMPERE2, 0); 5886 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_AMPERE2, 1); 5887 ii++; 5888 root["result"][ii]["val"] = NTYPE_AMPERE3; 5889 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_AMPERE3, 0); 5890 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_AMPERE3, 1); 5891 ii++; 5892 } 5893 if ((dType == pTypeCURRENTENERGY) && (dSubType == sTypeELEC4)) 5894 { 5895 root["result"][ii]["val"] = NTYPE_AMPERE1; 5896 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_AMPERE1, 0); 5897 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_AMPERE1, 1); 5898 ii++; 5899 root["result"][ii]["val"] = NTYPE_AMPERE2; 5900 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_AMPERE2, 0); 5901 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_AMPERE2, 1); 5902 ii++; 5903 root["result"][ii]["val"] = NTYPE_AMPERE3; 5904 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_AMPERE3, 0); 5905 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_AMPERE3, 1); 5906 ii++; 5907 } 5908 if (dType == pTypeP1Power) 5909 { 5910 root["result"][ii]["val"] = NTYPE_USAGE; 5911 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5912 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5913 ii++; 5914 root["result"][ii]["val"] = NTYPE_TODAYENERGY; 5915 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_TODAYENERGY, 0); 5916 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_TODAYENERGY, 1); 5917 ii++; 5918 } 5919 if (dType == pTypeP1Gas) 5920 { 5921 root["result"][ii]["val"] = NTYPE_TODAYGAS; 5922 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_TODAYGAS, 0); 5923 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_TODAYGAS, 1); 5924 ii++; 5925 } 5926 if ((dType == pTypeThermostat) && (dSubType == sTypeThermSetpoint)) 5927 { 5928 root["result"][ii]["val"] = NTYPE_TEMPERATURE; 5929 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_TEMPERATURE, 0); 5930 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_TEMPERATURE, 1); 5931 ii++; 5932 } 5933 if (dType == pTypeEvohomeZone) 5934 { 5935 root["result"][ii]["val"] = NTYPE_TEMPERATURE; 5936 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_SETPOINT, 0); //FIXME NTYPE_SETPOINT implementation? 5937 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_SETPOINT, 1); 5938 ii++; 5939 } 5940 if ((dType == pTypeRFXSensor) && ((dSubType == sTypeRFXSensorAD) || (dSubType == sTypeRFXSensorVolt))) 5941 { 5942 root["result"][ii]["val"] = NTYPE_USAGE; 5943 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5944 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5945 ii++; 5946 } 5947 if ((dType == pTypeGeneral) && (dSubType == sTypePercentage)) 5948 { 5949 root["result"][ii]["val"] = NTYPE_PERCENTAGE; 5950 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_PERCENTAGE, 0); 5951 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_PERCENTAGE, 1); 5952 ii++; 5953 } 5954 if ((dType == pTypeGeneral) && (dSubType == sTypeWaterflow)) 5955 { 5956 root["result"][ii]["val"] = NTYPE_USAGE; 5957 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5958 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5959 ii++; 5960 } 5961 if ((dType == pTypeGeneral) && (dSubType == sTypeCustom)) 5962 { 5963 root["result"][ii]["val"] = NTYPE_USAGE; 5964 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5965 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5966 ii++; 5967 } 5968 if ((dType == pTypeGeneral) && (dSubType == sTypeFan)) 5969 { 5970 root["result"][ii]["val"] = NTYPE_RPM; 5971 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_RPM, 0); 5972 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_RPM, 1); 5973 ii++; 5974 } 5975 if ((dType == pTypeGeneral) && (dSubType == sTypeAlert)) 5976 { 5977 root["result"][ii]["val"] = NTYPE_USAGE; 5978 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_USAGE, 0); 5979 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_USAGE, 1); 5980 ii++; 5981 } 5982 if ((dType == pTypeGeneral) && (dSubType == sTypeZWaveAlarm)) 5983 { 5984 root["result"][ii]["val"] = NTYPE_VALUE; 5985 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_VALUE, 0); 5986 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_VALUE, 1); 5987 ii++; 5988 } 5989 if ((dType == pTypeRego6XXValue) && (dSubType == sTypeRego6XXStatus)) 5990 { 5991 root["result"][ii]["val"] = NTYPE_SWITCH_ON; 5992 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_SWITCH_ON, 0); 5993 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_SWITCH_ON, 1); 5994 ii++; 5995 root["result"][ii]["val"] = NTYPE_SWITCH_OFF; 5996 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_SWITCH_OFF, 0); 5997 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_SWITCH_OFF, 1); 5998 ii++; 5999 } 6000 if (!IsLightOrSwitch(dType, dSubType)) 6001 { 6002 root["result"][ii]["val"] = NTYPE_LASTUPDATE; 6003 root["result"][ii]["text"] = Notification_Type_Desc(NTYPE_LASTUPDATE, 0); 6004 root["result"][ii]["ptag"] = Notification_Type_Desc(NTYPE_LASTUPDATE, 1); 6005 ii++; 6006 } 6007 } 6008 else if (cparam == "addnotification") 6009 { 6010 if (session.rights < 2) 6011 { 6012 session.reply_status = reply::forbidden; 6013 return; //Only admin user allowed 6014 } 6015 6016 std::string idx = request::findValue(&req, "idx"); 6017 if (idx.empty()) 6018 return; 6019 6020 std::string stype = request::findValue(&req, "ttype"); 6021 std::string swhen = request::findValue(&req, "twhen"); 6022 std::string svalue = request::findValue(&req, "tvalue"); 6023 std::string scustommessage = request::findValue(&req, "tmsg"); 6024 std::string sactivesystems = request::findValue(&req, "tsystems"); 6025 std::string spriority = request::findValue(&req, "tpriority"); 6026 std::string ssendalways = request::findValue(&req, "tsendalways"); 6027 std::string srecovery = (request::findValue(&req, "trecovery") == "true") ? "1" : "0"; 6028 6029 if ((stype.empty()) || (swhen.empty()) || (svalue.empty()) || (spriority.empty()) || (ssendalways.empty()) || (srecovery.empty())) 6030 return; 6031 6032 _eNotificationTypes ntype = (_eNotificationTypes)atoi(stype.c_str()); 6033 std::string ttype = Notification_Type_Desc(ntype, 1); 6034 if ( 6035 (ntype == NTYPE_SWITCH_ON) || 6036 (ntype == NTYPE_SWITCH_OFF) || 6037 (ntype == NTYPE_DEWPOINT) 6038 ) 6039 { 6040 if ((ntype == NTYPE_SWITCH_ON) && (swhen == "2")) { // '=' 6041 unsigned char twhen = '='; 6042 sprintf(szTmp, "%s;%c;%s", ttype.c_str(), twhen, svalue.c_str()); 6043 } 6044 else 6045 strcpy(szTmp, ttype.c_str()); 6046 } 6047 else 6048 { 6049 std::string twhen; 6050 if (swhen == "0") 6051 twhen = ">"; 6052 else if (swhen == "1") 6053 twhen = ">="; 6054 else if (swhen == "2") 6055 twhen = "="; 6056 else if (swhen == "3") 6057 twhen = "!="; 6058 else if (swhen == "4") 6059 twhen = "<="; 6060 else 6061 twhen = "<"; 6062 sprintf(szTmp, "%s;%s;%s;%s", ttype.c_str(), twhen.c_str(), svalue.c_str(), srecovery.c_str()); 6063 } 6064 int priority = atoi(spriority.c_str()); 6065 bool bOK = m_notifications.AddNotification(idx, szTmp, scustommessage, sactivesystems, priority, (ssendalways == "true") ? true : false); 6066 if (bOK) { 6067 root["status"] = "OK"; 6068 root["title"] = "AddNotification"; 6069 } 6070 } 6071 else if (cparam == "updatenotification") 6072 { 6073 if (session.rights < 2) 6074 { 6075 session.reply_status = reply::forbidden; 6076 return; //Only admin user allowed 6077 } 6078 6079 std::string idx = request::findValue(&req, "idx"); 6080 std::string devidx = request::findValue(&req, "devidx"); 6081 if ((idx.empty()) || (devidx.empty())) 6082 return; 6083 6084 std::string stype = request::findValue(&req, "ttype"); 6085 std::string swhen = request::findValue(&req, "twhen"); 6086 std::string svalue = request::findValue(&req, "tvalue"); 6087 std::string scustommessage = request::findValue(&req, "tmsg"); 6088 std::string sactivesystems = request::findValue(&req, "tsystems"); 6089 std::string spriority = request::findValue(&req, "tpriority"); 6090 std::string ssendalways = request::findValue(&req, "tsendalways"); 6091 std::string srecovery = (request::findValue(&req, "trecovery") == "true") ? "1" : "0"; 6092 6093 if ((stype.empty()) || (swhen.empty()) || (svalue.empty()) || (spriority.empty()) || (ssendalways.empty()) || srecovery.empty()) 6094 return; 6095 root["status"] = "OK"; 6096 root["title"] = "UpdateNotification"; 6097 6098 std::string recoverymsg; 6099 if ((srecovery == "1") && (m_notifications.CustomRecoveryMessage(strtoull(idx.c_str(), NULL, 0), recoverymsg, true))) 6100 { 6101 scustommessage.append(";;"); 6102 scustommessage.append(recoverymsg); 6103 } 6104 //delete old record 6105 m_notifications.RemoveNotification(idx); 6106 6107 _eNotificationTypes ntype = (_eNotificationTypes)atoi(stype.c_str()); 6108 std::string ttype = Notification_Type_Desc(ntype, 1); 6109 if ( 6110 (ntype == NTYPE_SWITCH_ON) || 6111 (ntype == NTYPE_SWITCH_OFF) || 6112 (ntype == NTYPE_DEWPOINT) 6113 ) 6114 { 6115 if ((ntype == NTYPE_SWITCH_ON) && (swhen == "2")) { // '=' 6116 unsigned char twhen = '='; 6117 sprintf(szTmp, "%s;%c;%s", ttype.c_str(), twhen, svalue.c_str()); 6118 } 6119 else 6120 strcpy(szTmp, ttype.c_str()); 6121 } 6122 else 6123 { 6124 std::string twhen; 6125 if (swhen == "0") 6126 twhen = ">"; 6127 else if (swhen == "1") 6128 twhen = ">="; 6129 else if (swhen == "2") 6130 twhen = "="; 6131 else if (swhen == "3") 6132 twhen = "!="; 6133 else if (swhen == "4") 6134 twhen = "<="; 6135 else 6136 twhen = "<"; 6137 sprintf(szTmp, "%s;%s;%s;%s", ttype.c_str(), twhen.c_str(), svalue.c_str(), srecovery.c_str()); 6138 } 6139 int priority = atoi(spriority.c_str()); 6140 m_notifications.AddNotification(devidx, szTmp, scustommessage, sactivesystems, priority, (ssendalways == "true") ? true : false); 6141 } 6142 else if (cparam == "deletenotification") 6143 { 6144 if (session.rights < 2) 6145 { 6146 session.reply_status = reply::forbidden; 6147 return; //Only admin user allowed 6148 } 6149 6150 std::string idx = request::findValue(&req, "idx"); 6151 if (idx.empty()) 6152 return; 6153 6154 root["status"] = "OK"; 6155 root["title"] = "DeleteNotification"; 6156 6157 m_notifications.RemoveNotification(idx); 6158 } 6159 else if (cparam == "switchdeviceorder") 6160 { 6161 if (session.rights < 2) 6162 { 6163 session.reply_status = reply::forbidden; 6164 return; //Only admin user allowed 6165 } 6166 6167 std::string idx1 = request::findValue(&req, "idx1"); 6168 std::string idx2 = request::findValue(&req, "idx2"); 6169 if ((idx1.empty()) || (idx2.empty())) 6170 return; 6171 std::string sroomid = request::findValue(&req, "roomid"); 6172 int roomid = atoi(sroomid.c_str()); 6173 6174 std::string Order1, Order2; 6175 if (roomid == 0) 6176 { 6177 //get device order 1 6178 result = m_sql.safe_query("SELECT [Order] FROM DeviceStatus WHERE (ID == '%q')", 6179 idx1.c_str()); 6180 if (result.empty()) 6181 return; 6182 Order1 = result[0][0]; 6183 6184 //get device order 2 6185 result = m_sql.safe_query("SELECT [Order] FROM DeviceStatus WHERE (ID == '%q')", 6186 idx2.c_str()); 6187 if (result.empty()) 6188 return; 6189 Order2 = result[0][0]; 6190 6191 root["status"] = "OK"; 6192 root["title"] = "SwitchDeviceOrder"; 6193 6194 if (atoi(Order1.c_str()) < atoi(Order2.c_str())) 6195 { 6196 m_sql.safe_query( 6197 "UPDATE DeviceStatus SET [Order] = [Order]+1 WHERE ([Order] >= '%q' AND [Order] < '%q')", 6198 Order1.c_str(), Order2.c_str()); 6199 } 6200 else 6201 { 6202 m_sql.safe_query( 6203 "UPDATE DeviceStatus SET [Order] = [Order]-1 WHERE ([Order] > '%q' AND [Order] <= '%q')", 6204 Order2.c_str(), Order1.c_str()); 6205 } 6206 6207 m_sql.safe_query("UPDATE DeviceStatus SET [Order] = '%q' WHERE (ID == '%q')", 6208 Order1.c_str(), idx2.c_str()); 6209 } 6210 else 6211 { 6212 //change order in a room 6213 //get device order 1 6214 result = m_sql.safe_query("SELECT [Order] FROM DeviceToPlansMap WHERE (DeviceRowID == '%q') AND (PlanID==%d)", 6215 idx1.c_str(), roomid); 6216 if (result.empty()) 6217 return; 6218 Order1 = result[0][0]; 6219 6220 //get device order 2 6221 result = m_sql.safe_query("SELECT [Order] FROM DeviceToPlansMap WHERE (DeviceRowID == '%q') AND (PlanID==%d)", 6222 idx2.c_str(), roomid); 6223 if (result.empty()) 6224 return; 6225 Order2 = result[0][0]; 6226 6227 root["status"] = "OK"; 6228 root["title"] = "SwitchDeviceOrder"; 6229 6230 if (atoi(Order1.c_str()) < atoi(Order2.c_str())) 6231 { 6232 m_sql.safe_query( 6233 "UPDATE DeviceToPlansMap SET [Order] = [Order]+1 WHERE ([Order] >= '%q' AND [Order] < '%q') AND (PlanID==%d)", 6234 Order1.c_str(), Order2.c_str(), roomid); 6235 } 6236 else 6237 { 6238 m_sql.safe_query( 6239 "UPDATE DeviceToPlansMap SET [Order] = [Order]-1 WHERE ([Order] > '%q' AND [Order] <= '%q') AND (PlanID==%d)", 6240 Order2.c_str(), Order1.c_str(), roomid); 6241 } 6242 6243 m_sql.safe_query("UPDATE DeviceToPlansMap SET [Order] = '%q' WHERE (DeviceRowID == '%q') AND (PlanID==%d)", 6244 Order1.c_str(), idx2.c_str(), roomid); 6245 } 6246 } 6247 else if (cparam == "switchsceneorder") 6248 { 6249 if (session.rights < 2) 6250 { 6251 session.reply_status = reply::forbidden; 6252 return; //Only admin user allowed 6253 } 6254 6255 std::string idx1 = request::findValue(&req, "idx1"); 6256 std::string idx2 = request::findValue(&req, "idx2"); 6257 if ((idx1.empty()) || (idx2.empty())) 6258 return; 6259 6260 std::string Order1, Order2; 6261 //get device order 1 6262 result = m_sql.safe_query("SELECT [Order] FROM Scenes WHERE (ID == '%q')", 6263 idx1.c_str()); 6264 if (result.empty()) 6265 return; 6266 Order1 = result[0][0]; 6267 6268 //get device order 2 6269 result = m_sql.safe_query("SELECT [Order] FROM Scenes WHERE (ID == '%q')", 6270 idx2.c_str()); 6271 if (result.empty()) 6272 return; 6273 Order2 = result[0][0]; 6274 6275 root["status"] = "OK"; 6276 root["title"] = "SwitchSceneOrder"; 6277 6278 if (atoi(Order1.c_str()) < atoi(Order2.c_str())) 6279 { 6280 m_sql.safe_query( 6281 "UPDATE Scenes SET [Order] = [Order]+1 WHERE ([Order] >= '%q' AND [Order] < '%q')", 6282 Order1.c_str(), Order2.c_str()); 6283 } 6284 else 6285 { 6286 m_sql.safe_query( 6287 "UPDATE Scenes SET [Order] = [Order]-1 WHERE ([Order] > '%q' AND [Order] <= '%q')", 6288 Order2.c_str(), Order1.c_str()); 6289 } 6290 6291 m_sql.safe_query("UPDATE Scenes SET [Order] = '%q' WHERE (ID == '%q')", 6292 Order1.c_str(), idx2.c_str()); 6293 } 6294 else if (cparam == "clearnotifications") 6295 { 6296 if (session.rights < 2) 6297 { 6298 session.reply_status = reply::forbidden; 6299 return; //Only admin user allowed 6300 } 6301 6302 std::string idx = request::findValue(&req, "idx"); 6303 if (idx.empty()) 6304 return; 6305 6306 root["status"] = "OK"; 6307 root["title"] = "ClearNotification"; 6308 6309 m_notifications.RemoveDeviceNotifications(idx); 6310 } 6311 else if (cparam == "adduser") 6312 { 6313 if (session.rights < 2) 6314 { 6315 session.reply_status = reply::forbidden; 6316 return; //Only admin user allowed 6317 } 6318 6319 std::string senabled = request::findValue(&req, "enabled"); 6320 std::string username = request::findValue(&req, "username"); 6321 std::string password = request::findValue(&req, "password"); 6322 std::string srights = request::findValue(&req, "rights"); 6323 std::string sRemoteSharing = request::findValue(&req, "RemoteSharing"); 6324 std::string sTabsEnabled = request::findValue(&req, "TabsEnabled"); 6325 if ( 6326 (senabled.empty()) || 6327 (username.empty()) || 6328 (password.empty()) || 6329 (srights.empty()) || 6330 (sRemoteSharing.empty()) || 6331 (sTabsEnabled.empty()) 6332 ) 6333 return; 6334 int rights = atoi(srights.c_str()); 6335 if (rights != 2) 6336 { 6337 if (!FindAdminUser()) 6338 { 6339 root["message"] = "Add a Admin user first! (Or enable Settings/Website Protection)"; 6340 return; 6341 } 6342 } 6343 //Check for duplicate user name 6344 result = m_sql.safe_query("SELECT ID FROM Users WHERE (Username == '%q')", base64_encode(username).c_str()); 6345 if (!result.empty()) 6346 { 6347 root["message"] = "Duplicate Username!"; 6348 return; 6349 } 6350 root["status"] = "OK"; 6351 root["title"] = "AddUser"; 6352 m_sql.safe_query( 6353 "INSERT INTO Users (Active, Username, Password, Rights, RemoteSharing, TabsEnabled) VALUES (%d,'%q','%q','%d','%d','%d')", 6354 (senabled == "true") ? 1 : 0, 6355 base64_encode(username).c_str(), 6356 password.c_str(), 6357 rights, 6358 (sRemoteSharing == "true") ? 1 : 0, 6359 atoi(sTabsEnabled.c_str()) 6360 ); 6361 LoadUsers(); 6362 } 6363 else if (cparam == "updateuser") 6364 { 6365 if (session.rights < 2) 6366 { 6367 session.reply_status = reply::forbidden; 6368 return; //Only admin user allowed 6369 } 6370 6371 std::string idx = request::findValue(&req, "idx"); 6372 if (idx.empty()) 6373 return; 6374 std::string senabled = request::findValue(&req, "enabled"); 6375 std::string username = request::findValue(&req, "username"); 6376 std::string password = request::findValue(&req, "password"); 6377 std::string srights = request::findValue(&req, "rights"); 6378 std::string sRemoteSharing = request::findValue(&req, "RemoteSharing"); 6379 std::string sTabsEnabled = request::findValue(&req, "TabsEnabled"); 6380 if ( 6381 (senabled.empty()) || 6382 (username.empty()) || 6383 (password.empty()) || 6384 (srights.empty()) || 6385 (sRemoteSharing.empty()) || 6386 (sTabsEnabled.empty()) 6387 ) 6388 return; 6389 int rights = atoi(srights.c_str()); 6390 if (rights != 2) 6391 { 6392 if (!FindAdminUser()) 6393 { 6394 root["message"] = "Add a Admin user first! (Or enable Settings/Website Protection)"; 6395 return; 6396 } 6397 } 6398 std::string sHashedUsername = base64_encode(username); 6399 6400 //Check for duplicate user name 6401 result = m_sql.safe_query("SELECT ID FROM Users WHERE (Username == '%q')", base64_encode(username).c_str()); 6402 if (!result.empty()) 6403 { 6404 std::string oidx = result[0][0]; 6405 if (oidx != idx) 6406 { 6407 root["message"] = "Duplicate Username!"; 6408 return; 6409 } 6410 } 6411 6412 // Invalid user's sessions if username or password has changed 6413 std::string sOldUsername; 6414 std::string sOldPassword; 6415 result = m_sql.safe_query("SELECT Username, Password FROM Users WHERE (ID == '%q')", idx.c_str()); 6416 if (result.size() == 1) 6417 { 6418 sOldUsername = result[0][0]; 6419 sOldPassword = result[0][1]; 6420 } 6421 if ((sHashedUsername != sOldUsername) || (password != sOldPassword)) 6422 RemoveUsersSessions(sOldUsername, session); 6423 6424 root["status"] = "OK"; 6425 root["title"] = "UpdateUser"; 6426 m_sql.safe_query( 6427 "UPDATE Users SET Active=%d, Username='%q', Password='%q', Rights=%d, RemoteSharing=%d, TabsEnabled=%d WHERE (ID == '%q')", 6428 (senabled == "true") ? 1 : 0, 6429 sHashedUsername.c_str(), 6430 password.c_str(), 6431 rights, 6432 (sRemoteSharing == "true") ? 1 : 0, 6433 atoi(sTabsEnabled.c_str()), 6434 idx.c_str() 6435 ); 6436 LoadUsers(); 6437 6438 6439 } 6440 else if (cparam == "deleteuser") 6441 { 6442 if (session.rights < 2) 6443 { 6444 session.reply_status = reply::forbidden; 6445 return; //Only admin user allowed 6446 } 6447 6448 std::string idx = request::findValue(&req, "idx"); 6449 if (idx.empty()) 6450 return; 6451 6452 root["status"] = "OK"; 6453 root["title"] = "DeleteUser"; 6454 6455 // Remove user's sessions 6456 result = m_sql.safe_query("SELECT Username FROM Users WHERE (ID == '%q')", idx.c_str()); 6457 if (result.size() == 1) 6458 { 6459 RemoveUsersSessions(result[0][0], session); 6460 } 6461 6462 m_sql.safe_query("DELETE FROM Users WHERE (ID == '%q')", idx.c_str()); 6463 6464 m_sql.safe_query("DELETE FROM SharedDevices WHERE (SharedUserID == '%q')", idx.c_str()); 6465 6466 LoadUsers(); 6467 } 6468 else if (cparam == "clearlightlog") 6469 { 6470 if (session.rights < 2) 6471 { 6472 session.reply_status = reply::forbidden; 6473 return; //Only admin user allowed 6474 } 6475 6476 std::string idx = request::findValue(&req, "idx"); 6477 if (idx.empty()) 6478 return; 6479 //First get Device Type/SubType 6480 result = m_sql.safe_query("SELECT Type, SubType FROM DeviceStatus WHERE (ID == '%q')", 6481 idx.c_str()); 6482 if (result.empty()) 6483 return; 6484 6485 unsigned char dType = atoi(result[0][0].c_str()); 6486 unsigned char dSubType = atoi(result[0][1].c_str()); 6487 6488 if ( 6489 (dType != pTypeLighting1) && 6490 (dType != pTypeLighting2) && 6491 (dType != pTypeLighting3) && 6492 (dType != pTypeLighting4) && 6493 (dType != pTypeLighting5) && 6494 (dType != pTypeLighting6) && 6495 (dType != pTypeFan) && 6496 (dType != pTypeColorSwitch) && 6497 (dType != pTypeSecurity1) && 6498 (dType != pTypeSecurity2) && 6499 (dType != pTypeEvohome) && 6500 (dType != pTypeEvohomeRelay) && 6501 (dType != pTypeCurtain) && 6502 (dType != pTypeBlinds) && 6503 (dType != pTypeRFY) && 6504 (dType != pTypeChime) && 6505 (dType != pTypeThermostat2) && 6506 (dType != pTypeThermostat3) && 6507 (dType != pTypeThermostat4) && 6508 (dType != pTypeRemote) && 6509 (dType != pTypeGeneralSwitch) && 6510 (dType != pTypeHomeConfort) && 6511 (dType != pTypeFS20) && 6512 (!((dType == pTypeRadiator1) && (dSubType == sTypeSmartwaresSwitchRadiator))) && 6513 (!((dType == pTypeGeneral) && (dSubType == sTypeTextStatus))) && 6514 (!((dType == pTypeGeneral) && (dSubType == sTypeAlert))) && 6515 (dType != pTypeHunter) 6516 ) 6517 return; //no light device! we should not be here! 6518 6519 root["status"] = "OK"; 6520 root["title"] = "ClearLightLog"; 6521 6522 result = m_sql.safe_query("DELETE FROM LightingLog WHERE (DeviceRowID=='%q')", idx.c_str()); 6523 } 6524 else if (cparam == "clearscenelog") 6525 { 6526 if (session.rights < 2) 6527 { 6528 session.reply_status = reply::forbidden; 6529 return; //Only admin user allowed 6530 } 6531 6532 std::string idx = request::findValue(&req, "idx"); 6533 if (idx.empty()) 6534 return; 6535 root["status"] = "OK"; 6536 root["title"] = "ClearSceneLog"; 6537 6538 result = m_sql.safe_query("DELETE FROM SceneLog WHERE (SceneRowID=='%q')", idx.c_str()); 6539 } 6540 else if (cparam == "learnsw") 6541 { 6542 if (session.rights < 2) 6543 { 6544 session.reply_status = reply::forbidden; 6545 return; //Only admin user allowed 6546 } 6547 6548 m_sql.AllowNewHardwareTimer(5); 6549 m_sql.m_LastSwitchID = ""; 6550 bool bReceivedSwitch = false; 6551 unsigned char cntr = 0; 6552 while ((!bReceivedSwitch) && (cntr < 50)) //wait for max. 5 seconds 6553 { 6554 if (m_sql.m_LastSwitchID != "") 6555 { 6556 bReceivedSwitch = true; 6557 break; 6558 } 6559 else 6560 { 6561 //sleep 100ms 6562 sleep_milliseconds(100); 6563 cntr++; 6564 } 6565 } 6566 if (bReceivedSwitch) 6567 { 6568 //check if used 6569 result = m_sql.safe_query("SELECT Name, Used, nValue FROM DeviceStatus WHERE (ID==%" PRIu64 ")", 6570 m_sql.m_LastSwitchRowID); 6571 if (!result.empty()) 6572 { 6573 root["status"] = "OK"; 6574 root["title"] = "LearnSW"; 6575 root["ID"] = m_sql.m_LastSwitchID; 6576 root["idx"] = m_sql.m_LastSwitchRowID; 6577 root["Name"] = result[0][0]; 6578 root["Used"] = atoi(result[0][1].c_str()); 6579 root["Cmd"] = atoi(result[0][2].c_str()); 6580 } 6581 } 6582 } //learnsw 6583 else if (cparam == "makefavorite") 6584 { 6585 if (session.rights < 1) 6586 { 6587 session.reply_status = reply::forbidden; 6588 return; //Only admin user allowed 6589 } 6590 std::string idx = request::findValue(&req, "idx"); 6591 std::string sisfavorite = request::findValue(&req, "isfavorite"); 6592 if ((idx.empty()) || (sisfavorite.empty())) 6593 return; 6594 int isfavorite = atoi(sisfavorite.c_str()); 6595 6596 root["status"] = "OK"; 6597 root["title"] = "MakeFavorite"; 6598 6599 const int iUser = FindUser(session.username.c_str()); 6600 if (iUser != -1) 6601 { 6602 const _eUserRights urights = m_users[iUser].userrights; 6603 if ((urights != URIGHTS_ADMIN) && (m_users[iUser].ID != 0xFFFF)) 6604 { 6605 m_sql.safe_query("UPDATE SharedDevices SET Favorite=%d WHERE (DeviceRowID == '%q') AND (SharedUserID == %d)", isfavorite, idx.c_str(), m_users[iUser].ID); 6606 return; 6607 } 6608 } 6609 m_sql.safe_query("UPDATE DeviceStatus SET Favorite=%d WHERE (ID == '%q')", isfavorite, idx.c_str()); 6610 } //makefavorite 6611 else if (cparam == "makescenefavorite") 6612 { 6613 if (session.rights < 2) 6614 { 6615 session.reply_status = reply::forbidden; 6616 return; //Only admin user allowed 6617 } 6618 6619 std::string idx = request::findValue(&req, "idx"); 6620 std::string sisfavorite = request::findValue(&req, "isfavorite"); 6621 if ((idx.empty()) || (sisfavorite.empty())) 6622 return; 6623 int isfavorite = atoi(sisfavorite.c_str()); 6624 m_sql.safe_query("UPDATE Scenes SET Favorite=%d WHERE (ID == '%q')", 6625 isfavorite, idx.c_str()); 6626 root["status"] = "OK"; 6627 root["title"] = "MakeSceneFavorite"; 6628 } //makescenefavorite 6629 else if (cparam == "resetsecuritystatus") 6630 { 6631 std::string idx = request::findValue(&req, "idx"); 6632 std::string switchcmd = request::findValue(&req, "switchcmd"); 6633 6634 if ((idx.empty()) || (switchcmd.empty())) 6635 return; 6636 6637 root["status"] = "OK"; 6638 root["title"] = "ResetSecurityStatus"; 6639 6640 int nValue = -1; 6641 6642 // Change to generic *Security_Status_Desc lookup... 6643 6644 if (switchcmd == "Panic End") { 6645 nValue = 7; 6646 } 6647 else if (switchcmd == "Normal") { 6648 nValue = 0; 6649 } 6650 6651 if (nValue >= 0) 6652 { 6653 m_sql.safe_query("UPDATE DeviceStatus SET nValue=%d WHERE (ID == '%q')", 6654 nValue, idx.c_str()); 6655 root["status"] = "OK"; 6656 root["title"] = "SwitchLight"; 6657 } 6658 } 6659 else if (cparam == "verifypasscode") 6660 { 6661 std::string passcode = request::findValue(&req, "passcode"); 6662 if (passcode.empty()) 6663 return; 6664 //Check if passcode is correct 6665 passcode = GenerateMD5Hash(passcode); 6666 std::string rpassword; 6667 int nValue = 1; 6668 m_sql.GetPreferencesVar("ProtectionPassword", nValue, rpassword); 6669 if (passcode == rpassword) 6670 { 6671 root["title"] = "VerifyPasscode"; 6672 root["status"] = "OK"; 6673 return; 6674 } 6675 } 6676 else if (cparam == "switchmodal") 6677 { 6678 int urights = 3; 6679 if (bHaveUser) 6680 { 6681 int iUser = -1; 6682 iUser = FindUser(session.username.c_str()); 6683 if (iUser != -1) 6684 { 6685 urights = (int)m_users[iUser].userrights; 6686 _log.Log(LOG_STATUS, "User: %s initiated a modal command", m_users[iUser].Username.c_str()); 6687 } 6688 } 6689 if (urights < 1) 6690 return; 6691 6692 std::string idx = request::findValue(&req, "idx"); 6693 std::string switchcmd = request::findValue(&req, "status"); 6694 std::string until = request::findValue(&req, "until");//optional until date / time as applicable 6695 std::string action = request::findValue(&req, "action");//Run action or not (update status only) 6696 std::string onlyonchange = request::findValue(&req, "ooc");//No update unless the value changed (check if updated) 6697 //The on action is used to call a script to update the real device so we only want to use it when altering the status in the Domoticz Web Client 6698 //If we're posting the status from the real device to domoticz we don't want to run the on action script ("action"!=1) to avoid loops and contention 6699 //""... we only want to log a change (and trigger an event) when the status has actually changed ("ooc"==1) i.e. suppress non transient updates 6700 if ((idx.empty()) || (switchcmd.empty())) 6701 return; 6702 6703 std::string passcode = request::findValue(&req, "passcode"); 6704 if (passcode.size() > 0) 6705 { 6706 //Check if passcode is correct 6707 passcode = GenerateMD5Hash(passcode); 6708 std::string rpassword; 6709 int nValue = 1; 6710 m_sql.GetPreferencesVar("ProtectionPassword", nValue, rpassword); 6711 if (passcode != rpassword) 6712 { 6713 root["title"] = "Modal"; 6714 root["status"] = "ERROR"; 6715 root["message"] = "WRONG CODE"; 6716 return; 6717 } 6718 } 6719 6720 if (m_mainworker.SwitchModal(idx, switchcmd, action, onlyonchange, until) == true)//FIXME we need to return a status of already set / no update if ooc=="1" and no status update was performed 6721 { 6722 root["status"] = "OK"; 6723 root["title"] = "Modal"; 6724 } 6725 } 6726 else if (cparam == "switchlight") 6727 { 6728 if (session.rights < 1) 6729 { 6730 session.reply_status = reply::forbidden; 6731 return; //Only user/admin allowed 6732 } 6733 std::string Username = "Admin"; 6734 if (!session.username.empty()) 6735 Username = session.username; 6736 6737 std::string idx = request::findValue(&req, "idx"); 6738 6739 std::string switchcmd = request::findValue(&req, "switchcmd"); 6740 std::string level = "-1"; 6741 if (switchcmd == "Set Level") 6742 level = request::findValue(&req, "level"); 6743 std::string onlyonchange = request::findValue(&req, "ooc");//No update unless the value changed (check if updated) 6744 _log.Debug(DEBUG_WEBSERVER, "WEBS switchlight idx:%s switchcmd:%s level:%s", idx.c_str(), switchcmd.c_str(), level.c_str()); 6745 std::string passcode = request::findValue(&req, "passcode"); 6746 if ((idx.empty()) || (switchcmd.empty()) || ((switchcmd == "Set Level") && (level.empty())) ) 6747 return; 6748 6749 result = m_sql.safe_query( 6750 "SELECT [Protected],[Name] FROM DeviceStatus WHERE (ID = '%q')", idx.c_str()); 6751 if (result.empty()) 6752 { 6753 //Switch not found! 6754 _log.Log(LOG_ERROR, "User: %s, switch not found (idx=%s)!", Username.c_str(), idx.c_str()); 6755 return; 6756 } 6757 bool bIsProtected = atoi(result[0][0].c_str()) != 0; 6758 std::string sSwitchName = result[0][1]; 6759 if (session.rights == 1) 6760 { 6761 if (!IsIdxForUser(&session, atoi(idx.c_str()))) 6762 { 6763 _log.Log(LOG_ERROR, "User: %s initiated a Unauthorized switch command!", Username.c_str()); 6764 session.reply_status = reply::forbidden; 6765 return; 6766 } 6767 } 6768 6769 if (bIsProtected) 6770 { 6771 if (passcode.empty()) 6772 { 6773 //Switch is protected, but no passcode has been 6774 root["title"] = "SwitchLight"; 6775 root["status"] = "ERROR"; 6776 root["message"] = "WRONG CODE"; 6777 return; 6778 } 6779 //Check if passcode is correct 6780 passcode = GenerateMD5Hash(passcode); 6781 std::string rpassword; 6782 int nValue = 1; 6783 m_sql.GetPreferencesVar("ProtectionPassword", nValue, rpassword); 6784 if (passcode != rpassword) 6785 { 6786 _log.Log(LOG_ERROR, "User: %s initiated a switch command (Wrong code!)", Username.c_str()); 6787 root["title"] = "SwitchLight"; 6788 root["status"] = "ERROR"; 6789 root["message"] = "WRONG CODE"; 6790 return; 6791 } 6792 } 6793 6794 _log.Log(LOG_STATUS, "User: %s initiated a switch command (%s/%s/%s)", Username.c_str(), idx.c_str(), sSwitchName.c_str(), switchcmd.c_str()); 6795 6796 root["title"] = "SwitchLight"; 6797 if (m_mainworker.SwitchLight(idx, switchcmd, level, "-1", onlyonchange, 0, Username) == true) 6798 { 6799 root["status"] = "OK"; 6800 } 6801 else 6802 { 6803 root["status"] = "ERROR"; 6804 root["message"] = "Error sending switch command, check device/hardware (idx=" + idx + ") !"; 6805 } 6806 } //(rtype=="switchlight") 6807 else if (cparam == "switchscene") 6808 { 6809 if (session.rights < 1) 6810 { 6811 session.reply_status = reply::forbidden; 6812 return; //Only user/admin allowed 6813 } 6814 std::string Username = "Admin"; 6815 if (!session.username.empty()) 6816 Username = session.username; 6817 6818 std::string idx = request::findValue(&req, "idx"); 6819 std::string switchcmd = request::findValue(&req, "switchcmd"); 6820 std::string passcode = request::findValue(&req, "passcode"); 6821 if ((idx.empty()) || (switchcmd.empty())) 6822 return; 6823 6824 result = m_sql.safe_query( 6825 "SELECT [Protected] FROM Scenes WHERE (ID = '%q')", idx.c_str()); 6826 if (result.empty()) 6827 { 6828 //Scene/Group not found! 6829 _log.Log(LOG_ERROR, "User: %s, scene not found (idx=%s)!", Username.c_str(), idx.c_str()); 6830 return; 6831 } 6832 bool bIsProtected = atoi(result[0][0].c_str()) != 0; 6833 if (bIsProtected) 6834 { 6835 if (passcode.empty()) 6836 { 6837 root["title"] = "SwitchScene"; 6838 root["status"] = "ERROR"; 6839 root["message"] = "WRONG CODE"; 6840 return; 6841 } 6842 //Check if passcode is correct 6843 passcode = GenerateMD5Hash(passcode); 6844 std::string rpassword; 6845 int nValue = 1; 6846 m_sql.GetPreferencesVar("ProtectionPassword", nValue, rpassword); 6847 if (passcode != rpassword) 6848 { 6849 root["title"] = "SwitchScene"; 6850 root["status"] = "ERROR"; 6851 root["message"] = "WRONG CODE"; 6852 _log.Log(LOG_ERROR, "User: %s initiated a scene/group command (Wrong code!)", Username.c_str()); 6853 return; 6854 } 6855 } 6856 _log.Log(LOG_STATUS, "User: %s initiated a scene/group command", Username.c_str()); 6857 6858 if (m_mainworker.SwitchScene(idx, switchcmd, Username) == true) 6859 { 6860 root["status"] = "OK"; 6861 root["title"] = "SwitchScene"; 6862 } 6863 } //(rtype=="switchscene") 6864 else if (cparam == "getSunRiseSet") { 6865 if (!m_mainworker.m_LastSunriseSet.empty()) 6866 { 6867 std::vector<std::string> strarray; 6868 StringSplit(m_mainworker.m_LastSunriseSet, ";", strarray); 6869 if (strarray.size() == 10) 6870 { 6871 struct tm loctime; 6872 time_t now = mytime(NULL); 6873 6874 localtime_r(&now, &loctime); 6875 //strftime(szTmp, 80, "%b %d %Y %X", &loctime); 6876 strftime(szTmp, 80, "%Y-%m-%d %X", &loctime); 6877 6878 root["status"] = "OK"; 6879 root["title"] = "getSunRiseSet"; 6880 root["ServerTime"] = szTmp; 6881 root["Sunrise"] = strarray[0]; 6882 root["Sunset"] = strarray[1]; 6883 root["SunAtSouth"] = strarray[2]; 6884 root["CivTwilightStart"] = strarray[3]; 6885 root["CivTwilightEnd"] = strarray[4]; 6886 root["NautTwilightStart"] = strarray[5]; 6887 root["NautTwilightEnd"] = strarray[6]; 6888 root["AstrTwilightStart"] = strarray[7]; 6889 root["AstrTwilightEnd"] = strarray[8]; 6890 root["DayLength"] = strarray[9]; 6891 } 6892 } 6893 } 6894 else if (cparam == "getServerTime") { 6895 6896 struct tm loctime; 6897 time_t now = mytime(NULL); 6898 6899 localtime_r(&now, &loctime); 6900 //strftime(szTmp, 80, "%b %d %Y %X", &loctime); 6901 strftime(szTmp, 80, "%Y-%m-%d %X", &loctime); 6902 6903 root["status"] = "OK"; 6904 root["title"] = "getServerTime"; 6905 root["ServerTime"] = szTmp; 6906 } 6907 else if (cparam == "getsecstatus") 6908 { 6909 root["status"] = "OK"; 6910 root["title"] = "GetSecStatus"; 6911 6912 int secstatus = 0; 6913 m_sql.GetPreferencesVar("SecStatus", secstatus); 6914 root["secstatus"] = secstatus; 6915 6916 int secondelay = 30; 6917 m_sql.GetPreferencesVar("SecOnDelay", secondelay); 6918 root["secondelay"] = secondelay; 6919 } 6920 else if (cparam == "setsecstatus") 6921 { 6922 std::string ssecstatus = request::findValue(&req, "secstatus"); 6923 std::string seccode = request::findValue(&req, "seccode"); 6924 if ((ssecstatus.empty()) || (seccode.empty())) 6925 { 6926 root["message"] = "WRONG CODE"; 6927 return; 6928 } 6929 root["title"] = "SetSecStatus"; 6930 std::string rpassword; 6931 int nValue = 1; 6932 m_sql.GetPreferencesVar("SecPassword", nValue, rpassword); 6933 if (seccode != rpassword) 6934 { 6935 root["status"] = "ERROR"; 6936 root["message"] = "WRONG CODE"; 6937 return; 6938 } 6939 root["status"] = "OK"; 6940 int iSecStatus = atoi(ssecstatus.c_str()); 6941 m_mainworker.UpdateDomoticzSecurityStatus(iSecStatus); 6942 } 6943 else if (cparam == "setcolbrightnessvalue") 6944 { 6945 if (session.rights < 1) 6946 { 6947 session.reply_status = reply::forbidden; 6948 return; //Only user/admin allowed 6949 } 6950 6951 std::string Username = "Admin"; 6952 if (!session.username.empty()) 6953 Username = session.username; 6954 6955 std::string idx = request::findValue(&req, "idx"); 6956 6957 if (idx.empty()) 6958 { 6959 return; 6960 } 6961 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 6962 _tColor color; 6963 6964 std::string json = request::findValue(&req, "color"); 6965 std::string hex = request::findValue(&req, "hex"); 6966 std::string hue = request::findValue(&req, "hue"); 6967 std::string sat = request::findValue(&req, "sat"); 6968 std::string brightness = request::findValue(&req, "brightness"); 6969 std::string iswhite = request::findValue(&req, "iswhite"); 6970 6971 int ival = 100; 6972 float brightnessAdj = 1.0f; 6973 6974 if (!json.empty()) 6975 { 6976 color = _tColor(json); 6977 if (color.mode == ColorModeRGB) 6978 { 6979 // Normalize RGB to full brightness 6980 float hsb[3]; 6981 int r, g, b; 6982 rgb2hsb(color.r, color.g, color.b, hsb); 6983 hsb2rgb(hsb[0]*360.0f, hsb[1], 1.0f, r, g, b, 255); 6984 color.r = r; 6985 color.g = g; 6986 color.b = b; 6987 brightnessAdj = hsb[2]; 6988 } 6989 6990 //_log.Debug(DEBUG_WEBSERVER, "setcolbrightnessvalue: json: %s, color: '%s', bri: '%s'", json.c_str(), color.toString().c_str(), brightness.c_str()); 6991 } 6992 else if (!hex.empty()) 6993 { 6994 uint64_t ihex = hexstrtoui64(hex); 6995 //_log.Debug(DEBUG_WEBSERVER, "setcolbrightnessvalue: hex: '%s', ihex: %" PRIx64 ", bri: '%s', iswhite: '%s'", hex.c_str(), ihex, brightness.c_str(), iswhite.c_str()); 6996 uint8_t r = 0; 6997 uint8_t g = 0; 6998 uint8_t b = 0; 6999 uint8_t cw = 0; 7000 uint8_t ww = 0; 7001 switch (hex.length()) 7002 { 7003 case 6: //RGB 7004 r = (uint8_t)((ihex & 0x0000FF0000) >> 16); 7005 g = (uint8_t)((ihex & 0x000000FF00) >> 8); 7006 b = (uint8_t)ihex & 0xFF; 7007 float hsb[3]; 7008 int tr, tg, tb; // tmp of 'int' type so can be passed as references to hsb2rgb 7009 rgb2hsb(r, g, b, hsb); 7010 // Normalize RGB to full brightness 7011 hsb2rgb(hsb[0]*360.0f, hsb[1], 1.0f, tr, tg, tb, 255); 7012 r = tr; 7013 g = tg; 7014 b = tb; 7015 brightnessAdj = hsb[2]; 7016 // Backwards compatibility: set iswhite for unsaturated colors 7017 iswhite = (hsb[1] < (20.0 / 255.0)) ? "true" : "false"; 7018 color = _tColor(r, g, b, cw, ww, ColorModeRGB); 7019 break; 7020 case 8: //RGB_WW 7021 r = (uint8_t)((ihex & 0x00FF000000) >> 24); 7022 g = (uint8_t)((ihex & 0x0000FF0000) >> 16); 7023 b = (uint8_t)((ihex & 0x000000FF00) >> 8); 7024 ww = (uint8_t)ihex & 0xFF; 7025 color = _tColor(r, g, b, cw, ww, ColorModeCustom); 7026 break; 7027 case 10: //RGB_CW_WW 7028 r = (uint8_t)((ihex & 0xFF00000000) >> 32); 7029 g = (uint8_t)((ihex & 0x00FF000000) >> 24); 7030 b = (uint8_t)((ihex & 0x0000FF0000) >> 16); 7031 cw = (uint8_t)((ihex & 0x000000FF00) >> 8); 7032 ww = (uint8_t)ihex & 0xFF; 7033 color = _tColor(r, g, b, cw, ww, ColorModeCustom); 7034 break; 7035 } 7036 if (iswhite == "true") color.mode = ColorModeWhite; 7037 //_log.Debug(DEBUG_WEBSERVER, "setcolbrightnessvalue: rgbww: %02x%02x%02x%02x%02x, color: '%s'", r, g, b, cw, ww, color.toString().c_str()); 7038 } 7039 else if (!hue.empty()) 7040 { 7041 int r, g, b; 7042 7043 //convert hue to RGB 7044 float iHue = float(atof(hue.c_str())); 7045 float iSat = 100.0f; 7046 if (!sat.empty()) iSat = float(atof(sat.c_str())); 7047 hsb2rgb(iHue, iSat/100.0f, 1.0f, r, g, b, 255); 7048 7049 color = _tColor(r, g, b, 0, 0, ColorModeRGB); 7050 if (iswhite == "true") color.mode = ColorModeWhite; 7051 //_log.Debug(DEBUG_WEBSERVER, "setcolbrightnessvalue2: hue: %f, rgb: %02x%02x%02x, color: '%s'", iHue, r, g, b, color.toString().c_str()); 7052 } 7053 7054 if (color.mode == ColorModeNone) 7055 { 7056 return; 7057 } 7058 7059 if (!brightness.empty()) 7060 ival = atoi(brightness.c_str()); 7061 ival = int(ival * brightnessAdj); 7062 ival = std::max(ival, 0); 7063 ival = std::min(ival, 100); 7064 7065 _log.Log(LOG_STATUS, "setcolbrightnessvalue: ID: %" PRIx64 ", bri: %d, color: '%s'", ID, ival, color.toString().c_str()); 7066 m_mainworker.SwitchLight(ID, "Set Color", (unsigned char)ival, color, false, 0, Username); 7067 7068 root["status"] = "OK"; 7069 root["title"] = "SetColBrightnessValue"; 7070 } 7071 else if (cparam.find("setkelvinlevel") == 0) 7072 { 7073 if (session.rights < 1) 7074 { 7075 session.reply_status = reply::forbidden; 7076 return; //Only user/admin allowed 7077 } 7078 7079 std::string Username = "Admin"; 7080 if (!session.username.empty()) 7081 Username = session.username; 7082 7083 root["status"] = "OK"; 7084 root["title"] = "Set Kelvin Level"; 7085 7086 std::string idx = request::findValue(&req, "idx"); 7087 7088 if (idx.empty()) 7089 { 7090 return; 7091 } 7092 7093 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7094 7095 std::string kelvin = request::findValue(&req, "kelvin"); 7096 double ival = atof(kelvin.c_str()); 7097 ival = std::max(ival, 0.0); 7098 ival = std::min(ival, 100.0); 7099 _tColor color = _tColor(round(ival*255.0f/100.0f), ColorModeTemp); 7100 _log.Log(LOG_STATUS, "setkelvinlevel: t: %f, color: '%s'", ival, color.toString().c_str()); 7101 7102 m_mainworker.SwitchLight(ID, "Set Color", -1, color, false, 0, Username); 7103 } 7104 else if (cparam == "brightnessup") 7105 { 7106 if (session.rights < 1) 7107 { 7108 session.reply_status = reply::forbidden; 7109 return; //Only user/admin allowed 7110 } 7111 7112 std::string Username = "Admin"; 7113 if (!session.username.empty()) 7114 Username = session.username; 7115 7116 root["status"] = "OK"; 7117 root["title"] = "Set brightness up!"; 7118 7119 std::string idx = request::findValue(&req, "idx"); 7120 7121 if (idx.empty()) 7122 { 7123 return; 7124 } 7125 7126 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7127 m_mainworker.SwitchLight(ID, "Bright Up", 0, NoColor, false, 0, Username); 7128 } 7129 else if (cparam == "brightnessdown") 7130 { 7131 if (session.rights < 1) 7132 { 7133 session.reply_status = reply::forbidden; 7134 return; //Only user/admin allowed 7135 } 7136 7137 std::string Username = "Admin"; 7138 if (!session.username.empty()) 7139 Username = session.username; 7140 7141 root["status"] = "OK"; 7142 root["title"] = "Set brightness down!"; 7143 7144 std::string idx = request::findValue(&req, "idx"); 7145 7146 if (idx.empty()) 7147 { 7148 return; 7149 } 7150 7151 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7152 m_mainworker.SwitchLight(ID, "Bright Down", 0, NoColor, false, 0, Username); 7153 } 7154 else if (cparam == "discomode") 7155 { 7156 if (session.rights < 1) 7157 { 7158 session.reply_status = reply::forbidden; 7159 return; //Only user/admin allowed 7160 } 7161 7162 std::string Username = "Admin"; 7163 if (!session.username.empty()) 7164 Username = session.username; 7165 7166 root["status"] = "OK"; 7167 root["title"] = "Set to last known disco mode!"; 7168 7169 std::string idx = request::findValue(&req, "idx"); 7170 7171 if (idx.empty()) 7172 { 7173 return; 7174 } 7175 7176 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7177 m_mainworker.SwitchLight(ID, "Disco Mode", 0, NoColor, false, 0, Username); 7178 } 7179 else if (cparam.find("discomodenum") == 0 && cparam != "discomode" && cparam.size() == 13) 7180 { 7181 if (session.rights < 1) 7182 { 7183 session.reply_status = reply::forbidden; 7184 return; //Only user/admin allowed 7185 } 7186 7187 std::string Username = "Admin"; 7188 if (!session.username.empty()) 7189 Username = session.username; 7190 7191 root["status"] = "OK"; 7192 root["title"] = "Set to disco mode!"; 7193 7194 std::string idx = request::findValue(&req, "idx"); 7195 7196 if (idx.empty()) 7197 { 7198 return; 7199 } 7200 7201 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7202 char szTmp[40]; 7203 sprintf(szTmp, "Disco Mode %s", cparam.substr(12).c_str()); 7204 m_mainworker.SwitchLight(ID, szTmp, 0, NoColor, false, 0, Username); 7205 } 7206 else if (cparam == "discoup") 7207 { 7208 if (session.rights < 1) 7209 { 7210 session.reply_status = reply::forbidden; 7211 return; //Only user/admin allowed 7212 } 7213 7214 std::string Username = "Admin"; 7215 if (!session.username.empty()) 7216 Username = session.username; 7217 7218 root["status"] = "OK"; 7219 root["title"] = "Set to next disco mode!"; 7220 7221 std::string idx = request::findValue(&req, "idx"); 7222 7223 if (idx.empty()) 7224 { 7225 return; 7226 } 7227 7228 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7229 m_mainworker.SwitchLight(ID, "Disco Up", 0, NoColor, false, 0, Username); 7230 } 7231 else if (cparam == "discodown") 7232 { 7233 if (session.rights < 1) 7234 { 7235 session.reply_status = reply::forbidden; 7236 return; //Only user/admin allowed 7237 } 7238 7239 std::string Username = "Admin"; 7240 if (!session.username.empty()) 7241 Username = session.username; 7242 7243 root["status"] = "OK"; 7244 root["title"] = "Set to previous disco mode!"; 7245 7246 std::string idx = request::findValue(&req, "idx"); 7247 7248 if (idx.empty()) 7249 { 7250 return; 7251 } 7252 7253 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7254 m_mainworker.SwitchLight(ID, "Disco Down", 0, NoColor, false, 0, Username); 7255 } 7256 else if (cparam == "speedup") 7257 { 7258 if (session.rights < 1) 7259 { 7260 session.reply_status = reply::forbidden; 7261 return; //Only user/admin allowed 7262 } 7263 7264 std::string Username = "Admin"; 7265 if (!session.username.empty()) 7266 Username = session.username; 7267 7268 root["status"] = "OK"; 7269 root["title"] = "Set disco speed up!"; 7270 7271 std::string idx = request::findValue(&req, "idx"); 7272 7273 if (idx.empty()) 7274 { 7275 return; 7276 } 7277 7278 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7279 m_mainworker.SwitchLight(ID, "Speed Up", 0, NoColor, false, 0, Username); 7280 } 7281 else if (cparam == "speeduplong") 7282 { 7283 if (session.rights < 1) 7284 { 7285 session.reply_status = reply::forbidden; 7286 return; //Only user/admin allowed 7287 } 7288 7289 std::string Username = "Admin"; 7290 if (!session.username.empty()) 7291 Username = session.username; 7292 7293 root["status"] = "OK"; 7294 root["title"] = "Set speed long!"; 7295 7296 std::string idx = request::findValue(&req, "idx"); 7297 7298 if (idx.empty()) 7299 { 7300 return; 7301 } 7302 7303 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7304 m_mainworker.SwitchLight(ID, "Speed Up Long", 0, NoColor, false, 0, Username); 7305 } 7306 else if (cparam == "speeddown") 7307 { 7308 if (session.rights < 1) 7309 { 7310 session.reply_status = reply::forbidden; 7311 return; //Only user/admin allowed 7312 } 7313 7314 std::string Username = "Admin"; 7315 if (!session.username.empty()) 7316 Username = session.username; 7317 7318 root["status"] = "OK"; 7319 root["title"] = "Set disco speed down!"; 7320 7321 std::string idx = request::findValue(&req, "idx"); 7322 7323 if (idx.empty()) 7324 { 7325 return; 7326 } 7327 7328 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7329 m_mainworker.SwitchLight(ID, "Speed Down", 0, NoColor, false, 0, Username); 7330 } 7331 else if (cparam == "speedmin") 7332 { 7333 if (session.rights < 1) 7334 { 7335 session.reply_status = reply::forbidden; 7336 return; //Only user/admin allowed 7337 } 7338 7339 std::string Username = "Admin"; 7340 if (!session.username.empty()) 7341 Username = session.username; 7342 7343 root["status"] = "OK"; 7344 root["title"] = "Set disco speed minimal!"; 7345 7346 std::string idx = request::findValue(&req, "idx"); 7347 7348 if (idx.empty()) 7349 { 7350 return; 7351 } 7352 7353 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7354 m_mainworker.SwitchLight(ID, "Speed Minimal", 0, NoColor, false, 0, Username); 7355 } 7356 else if (cparam == "speedmax") 7357 { 7358 if (session.rights < 1) 7359 { 7360 session.reply_status = reply::forbidden; 7361 return; //Only user/admin allowed 7362 } 7363 7364 std::string Username = "Admin"; 7365 if (!session.username.empty()) 7366 Username = session.username; 7367 7368 root["status"] = "OK"; 7369 root["title"] = "Set disco speed maximal!"; 7370 7371 std::string idx = request::findValue(&req, "idx"); 7372 7373 if (idx.empty()) 7374 { 7375 return; 7376 } 7377 7378 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7379 m_mainworker.SwitchLight(ID, "Speed Maximal", 0, NoColor, false, 0, Username); 7380 } 7381 else if (cparam == "warmer") 7382 { 7383 if (session.rights < 1) 7384 { 7385 session.reply_status = reply::forbidden; 7386 return; //Only user/admin allowed 7387 } 7388 7389 std::string Username = "Admin"; 7390 if (!session.username.empty()) 7391 Username = session.username; 7392 7393 root["status"] = "OK"; 7394 root["title"] = "Set Kelvin up!"; 7395 7396 std::string idx = request::findValue(&req, "idx"); 7397 7398 if (idx.empty()) 7399 { 7400 return; 7401 } 7402 7403 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7404 m_mainworker.SwitchLight(ID, "Warmer", 0, NoColor, false, 0, Username); 7405 } 7406 else if (cparam == "cooler") 7407 { 7408 if (session.rights < 1) 7409 { 7410 session.reply_status = reply::forbidden; 7411 return; //Only user/admin allowed 7412 } 7413 7414 std::string Username = "Admin"; 7415 if (!session.username.empty()) 7416 Username = session.username; 7417 7418 root["status"] = "OK"; 7419 root["title"] = "Set Kelvin down!"; 7420 7421 std::string idx = request::findValue(&req, "idx"); 7422 7423 if (idx.empty()) 7424 { 7425 return; 7426 } 7427 7428 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7429 m_mainworker.SwitchLight(ID, "Cooler", 0, NoColor, false, 0, Username); 7430 } 7431 else if (cparam == "fulllight") 7432 { 7433 if (session.rights < 1) 7434 { 7435 session.reply_status = reply::forbidden; 7436 return; //Only user/admin allowed 7437 } 7438 7439 std::string Username = "Admin"; 7440 if (!session.username.empty()) 7441 Username = session.username; 7442 7443 root["status"] = "OK"; 7444 root["title"] = "Set Full!"; 7445 7446 std::string idx = request::findValue(&req, "idx"); 7447 7448 if (idx.empty()) 7449 { 7450 return; 7451 } 7452 7453 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7454 m_mainworker.SwitchLight(ID, "Set Full", 0, NoColor, false, 0, Username); 7455 } 7456 else if (cparam == "nightlight") 7457 { 7458 if (session.rights < 1) 7459 { 7460 session.reply_status = reply::forbidden; 7461 return; //Only user/admin allowed 7462 } 7463 7464 std::string Username = "Admin"; 7465 if (!session.username.empty()) 7466 Username = session.username; 7467 7468 root["status"] = "OK"; 7469 root["title"] = "Set to nightlight!"; 7470 7471 std::string idx = request::findValue(&req, "idx"); 7472 7473 if (idx.empty()) 7474 { 7475 return; 7476 } 7477 7478 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7479 m_mainworker.SwitchLight(ID, "Set Night", 0, NoColor, false, 0, Username); 7480 } 7481 else if (cparam == "whitelight") 7482 { 7483 if (session.rights < 1) 7484 { 7485 session.reply_status = reply::forbidden; 7486 return; //Only user/admin allowed 7487 } 7488 7489 std::string Username = "Admin"; 7490 if (!session.username.empty()) 7491 Username = session.username; 7492 7493 root["status"] = "OK"; 7494 root["title"] = "Set to clear white!"; 7495 7496 std::string idx = request::findValue(&req, "idx"); 7497 7498 if (idx.empty()) 7499 { 7500 return; 7501 } 7502 7503 uint64_t ID = std::strtoull(idx.c_str(), nullptr, 10); 7504 //TODO: Change to color with mode=ColorModeWhite and level=100? 7505 m_mainworker.SwitchLight(ID, "Set White", 0, NoColor, false, 0, Username); 7506 } 7507 else if (cparam == "getfloorplanimages") 7508 { 7509 root["status"] = "OK"; 7510 root["title"] = "GetFloorplanImages"; 7511 7512 bool bReturnUnused = atoi(request::findValue(&req, "unused").c_str()) != 0; 7513 7514 if (!bReturnUnused) 7515 result = m_sql.safe_query("SELECT ID, Name, ScaleFactor FROM Floorplans ORDER BY [Name]"); 7516 else 7517 result = m_sql.safe_query("SELECT ID, Name, ScaleFactor FROM Floorplans WHERE ID NOT IN(SELECT FloorplanID FROM Plans)"); 7518 if (!result.empty()) 7519 { 7520 int ii = 0; 7521 for (const auto & itt : result) 7522 { 7523 std::vector<std::string> sd = itt; 7524 7525 root["result"][ii]["idx"] = sd[0]; 7526 root["result"][ii]["name"] = sd[1]; 7527 root["result"][ii]["scalefactor"] = sd[2]; 7528 ii++; 7529 } 7530 } 7531 } 7532 else if (cparam == "updatefloorplan") 7533 { 7534 if (session.rights < 2) 7535 { 7536 session.reply_status = reply::forbidden; 7537 return; //Only admin user allowed 7538 } 7539 7540 std::string idx = request::findValue(&req, "idx"); 7541 if (idx.empty()) 7542 return; 7543 std::string name = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 7544 std::string scalefactor = request::findValue(&req, "scalefactor"); 7545 if ( 7546 (name.empty()) 7547 ||(scalefactor.empty()) 7548 ) 7549 return; 7550 7551 root["status"] = "OK"; 7552 root["title"] = "UpdateFloorplan"; 7553 7554 m_sql.safe_query( 7555 "UPDATE Floorplans SET Name='%q',ScaleFactor='%q' WHERE (ID == '%q')", 7556 name.c_str(), 7557 scalefactor.c_str(), 7558 idx.c_str() 7559 ); 7560 } 7561 else if (cparam == "deletefloorplan") 7562 { 7563 if (session.rights < 2) 7564 { 7565 session.reply_status = reply::forbidden; 7566 return; //Only admin user allowed 7567 } 7568 7569 std::string idx = request::findValue(&req, "idx"); 7570 if (idx.empty()) 7571 return; 7572 root["status"] = "OK"; 7573 root["title"] = "DeleteFloorplan"; 7574 m_sql.safe_query("UPDATE DeviceToPlansMap SET XOffset=0,YOffset=0 WHERE (PlanID IN (SELECT ID from Plans WHERE (FloorplanID == '%q')))", idx.c_str()); 7575 m_sql.safe_query("UPDATE Plans SET FloorplanID=0,Area='' WHERE (FloorplanID == '%q')", idx.c_str()); 7576 m_sql.safe_query("DELETE FROM Floorplans WHERE (ID == '%q')", idx.c_str()); 7577 } 7578 else if (cparam == "changefloorplanorder") 7579 { 7580 if (session.rights < 2) 7581 { 7582 session.reply_status = reply::forbidden; 7583 return; //Only admin user allowed 7584 } 7585 7586 std::string idx = request::findValue(&req, "idx"); 7587 if (idx.empty()) 7588 return; 7589 std::string sway = request::findValue(&req, "way"); 7590 if (sway.empty()) 7591 return; 7592 bool bGoUp = (sway == "0"); 7593 7594 std::string aOrder, oID, oOrder; 7595 7596 result = m_sql.safe_query("SELECT [Order] FROM Floorplans WHERE (ID=='%q')", 7597 idx.c_str()); 7598 if (result.empty()) 7599 return; 7600 aOrder = result[0][0]; 7601 7602 if (!bGoUp) 7603 { 7604 //Get next device order 7605 result = m_sql.safe_query("SELECT ID, [Order] FROM Floorplans WHERE ([Order]>'%q') ORDER BY [Order] ASC", 7606 aOrder.c_str()); 7607 if (result.empty()) 7608 return; 7609 oID = result[0][0]; 7610 oOrder = result[0][1]; 7611 } 7612 else 7613 { 7614 //Get previous device order 7615 result = m_sql.safe_query("SELECT ID, [Order] FROM Floorplans WHERE ([Order]<'%q') ORDER BY [Order] DESC", 7616 aOrder.c_str()); 7617 if (result.empty()) 7618 return; 7619 oID = result[0][0]; 7620 oOrder = result[0][1]; 7621 } 7622 //Swap them 7623 root["status"] = "OK"; 7624 root["title"] = "ChangeFloorPlanOrder"; 7625 7626 m_sql.safe_query("UPDATE Floorplans SET [Order] = '%q' WHERE (ID='%q')", 7627 oOrder.c_str(), idx.c_str()); 7628 m_sql.safe_query("UPDATE Floorplans SET [Order] = '%q' WHERE (ID='%q')", 7629 aOrder.c_str(), oID.c_str()); 7630 } 7631 else if (cparam == "getunusedfloorplanplans") 7632 { 7633 if (session.rights < 2) 7634 { 7635 session.reply_status = reply::forbidden; 7636 return; //Only admin user allowed 7637 } 7638 7639 root["status"] = "OK"; 7640 root["title"] = "GetUnusedFloorplanPlans"; 7641 int ii = 0; 7642 7643 result = m_sql.safe_query("SELECT ID, Name FROM Plans WHERE (FloorplanID==0) ORDER BY Name"); 7644 if (!result.empty()) 7645 { 7646 for (const auto & itt : result) 7647 { 7648 std::vector<std::string> sd = itt; 7649 7650 root["result"][ii]["type"] = 0; 7651 root["result"][ii]["idx"] = sd[0]; 7652 root["result"][ii]["Name"] = sd[1]; 7653 ii++; 7654 } 7655 } 7656 } 7657 else if (cparam == "getfloorplanplans") 7658 { 7659 std::string idx = request::findValue(&req, "idx"); 7660 if (idx.empty()) 7661 return; 7662 root["status"] = "OK"; 7663 root["title"] = "GetFloorplanPlans"; 7664 int ii = 0; 7665 result = m_sql.safe_query("SELECT ID, Name, Area FROM Plans WHERE (FloorplanID=='%q') ORDER BY Name", 7666 idx.c_str()); 7667 if (!result.empty()) 7668 { 7669 for (const auto & itt : result) 7670 { 7671 std::vector<std::string> sd = itt; 7672 7673 root["result"][ii]["idx"] = sd[0]; 7674 root["result"][ii]["Name"] = sd[1]; 7675 root["result"][ii]["Area"] = sd[2]; 7676 ii++; 7677 } 7678 } 7679 } 7680 else if (cparam == "addfloorplanplan") 7681 { 7682 if (session.rights < 2) 7683 { 7684 session.reply_status = reply::forbidden; 7685 return; //Only admin user allowed 7686 } 7687 7688 std::string idx = request::findValue(&req, "idx"); 7689 std::string planidx = request::findValue(&req, "planidx"); 7690 if ( 7691 (idx.empty()) || 7692 (planidx.empty()) 7693 ) 7694 return; 7695 root["status"] = "OK"; 7696 root["title"] = "AddFloorplanPlan"; 7697 7698 m_sql.safe_query( 7699 "UPDATE Plans SET FloorplanID='%q' WHERE (ID == '%q')", 7700 idx.c_str(), 7701 planidx.c_str() 7702 ); 7703 _log.Log(LOG_STATUS, "(Floorplan) Plan '%s' added to floorplan '%s'.", planidx.c_str(), idx.c_str()); 7704 } 7705 else if (cparam == "updatefloorplanplan") 7706 { 7707 if (session.rights < 2) 7708 { 7709 session.reply_status = reply::forbidden; 7710 return; //Only admin user allowed 7711 } 7712 7713 std::string planidx = request::findValue(&req, "planidx"); 7714 std::string planarea = request::findValue(&req, "area"); 7715 if (planidx.empty()) 7716 return; 7717 root["status"] = "OK"; 7718 root["title"] = "UpdateFloorplanPlan"; 7719 7720 m_sql.safe_query( 7721 "UPDATE Plans SET Area='%q' WHERE (ID == '%q')", 7722 planarea.c_str(), 7723 planidx.c_str() 7724 ); 7725 _log.Log(LOG_STATUS, "(Floorplan) Plan '%s' floor area updated to '%s'.", planidx.c_str(), planarea.c_str()); 7726 } 7727 else if (cparam == "deletefloorplanplan") 7728 { 7729 if (session.rights < 2) 7730 { 7731 session.reply_status = reply::forbidden; 7732 return; //Only admin user allowed 7733 } 7734 7735 std::string idx = request::findValue(&req, "idx"); 7736 if (idx.empty()) 7737 return; 7738 root["status"] = "OK"; 7739 root["title"] = "DeleteFloorplanPlan"; 7740 m_sql.safe_query( 7741 "UPDATE DeviceToPlansMap SET XOffset=0,YOffset=0 WHERE (PlanID == '%q')", 7742 idx.c_str() 7743 ); 7744 _log.Log(LOG_STATUS, "(Floorplan) Device coordinates reset for plan '%s'.", idx.c_str()); 7745 m_sql.safe_query( 7746 "UPDATE Plans SET FloorplanID=0,Area='' WHERE (ID == '%q')", 7747 idx.c_str() 7748 ); 7749 _log.Log(LOG_STATUS, "(Floorplan) Plan '%s' floorplan data reset.", idx.c_str()); 7750 } 7751 } 7752 DisplaySwitchTypesCombo(std::string & content_part)7753 void CWebServer::DisplaySwitchTypesCombo(std::string & content_part) 7754 { 7755 char szTmp[200]; 7756 7757 std::map<std::string, int> _switchtypes; 7758 7759 for (int ii = 0; ii < STYPE_END; ii++) 7760 { 7761 _switchtypes[Switch_Type_Desc((_eSwitchType)ii)] = ii; 7762 } 7763 //return a sorted list 7764 for (const auto & itt : _switchtypes) 7765 { 7766 sprintf(szTmp, "<option value=\"%d\">%s</option>\n", itt.second, itt.first.c_str()); 7767 content_part += szTmp; 7768 } 7769 } 7770 DisplayMeterTypesCombo(std::string & content_part)7771 void CWebServer::DisplayMeterTypesCombo(std::string & content_part) 7772 { 7773 char szTmp[200]; 7774 for (int ii = 0; ii < MTYPE_END; ii++) 7775 { 7776 sprintf(szTmp, "<option value=\"%d\">%s</option>\n", ii, Meter_Type_Desc((_eMeterType)ii)); 7777 content_part += szTmp; 7778 } 7779 } 7780 DisplayLanguageCombo(std::string & content_part)7781 void CWebServer::DisplayLanguageCombo(std::string & content_part) 7782 { 7783 //return a sorted list 7784 std::map<std::string, std::string> _ltypes; 7785 char szTmp[200]; 7786 int ii = 0; 7787 while (guiLanguage[ii].szShort != NULL) 7788 { 7789 _ltypes[guiLanguage[ii].szLong] = guiLanguage[ii].szShort; 7790 ii++; 7791 } 7792 for (const auto & itt : _ltypes) 7793 { 7794 sprintf(szTmp, "<option value=\"%s\">%s</option>\n", itt.second.c_str(), itt.first.c_str()); 7795 content_part += szTmp; 7796 } 7797 } 7798 DisplayTimerTypesCombo(std::string & content_part)7799 void CWebServer::DisplayTimerTypesCombo(std::string & content_part) 7800 { 7801 char szTmp[200]; 7802 for (int ii = 0; ii < TTYPE_END; ii++) 7803 { 7804 sprintf(szTmp, "<option data-i18n=\"%s\" value=\"%d\">%s</option>\n", Timer_Type_Desc(ii), ii, Timer_Type_Desc(ii)); 7805 content_part += szTmp; 7806 } 7807 } 7808 LoadUsers()7809 void CWebServer::LoadUsers() 7810 { 7811 ClearUserPasswords(); 7812 std::string WebUserName, WebPassword; 7813 int nValue = 0; 7814 if (m_sql.GetPreferencesVar("WebUserName", nValue, WebUserName)) 7815 { 7816 if (m_sql.GetPreferencesVar("WebPassword", nValue, WebPassword)) 7817 { 7818 if ((WebUserName != "") && (WebPassword != "")) 7819 { 7820 WebUserName = base64_decode(WebUserName); 7821 //WebPassword = WebPassword; 7822 AddUser(10000, WebUserName, WebPassword, URIGHTS_ADMIN, 0xFFFF); 7823 7824 std::vector<std::vector<std::string> > result; 7825 result = m_sql.safe_query("SELECT ID, Active, Username, Password, Rights, TabsEnabled FROM Users"); 7826 if (!result.empty()) 7827 { 7828 for (const auto & itt : result) 7829 { 7830 std::vector<std::string> sd = itt; 7831 7832 int bIsActive = static_cast<int>(atoi(sd[1].c_str())); 7833 if (bIsActive) 7834 { 7835 unsigned long ID = (unsigned long)atol(sd[0].c_str()); 7836 7837 std::string username = base64_decode(sd[2]); 7838 std::string password = sd[3]; 7839 7840 _eUserRights rights = (_eUserRights)atoi(sd[4].c_str()); 7841 int activetabs = atoi(sd[5].c_str()); 7842 7843 AddUser(ID, username, password, rights, activetabs); 7844 } 7845 } 7846 } 7847 } 7848 } 7849 } 7850 m_mainworker.LoadSharedUsers(); 7851 } 7852 AddUser(const unsigned long ID,const std::string & username,const std::string & password,const int userrights,const int activetabs)7853 void CWebServer::AddUser(const unsigned long ID, const std::string &username, const std::string &password, const int userrights, const int activetabs) 7854 { 7855 std::vector<std::vector<std::string> > result = m_sql.safe_query("SELECT COUNT(*) FROM SharedDevices WHERE (SharedUserID == '%d')", ID); 7856 if (result.empty()) 7857 return; 7858 7859 _tWebUserPassword wtmp; 7860 wtmp.ID = ID; 7861 wtmp.Username = username; 7862 wtmp.Password = password; 7863 wtmp.userrights = (_eUserRights)userrights; 7864 wtmp.ActiveTabs = activetabs; 7865 wtmp.TotSensors = atoi(result[0][0].c_str()); 7866 m_users.push_back(wtmp); 7867 7868 m_pWebEm->AddUserPassword(ID, username, password, (_eUserRights)userrights, activetabs); 7869 } 7870 ClearUserPasswords()7871 void CWebServer::ClearUserPasswords() 7872 { 7873 m_users.clear(); 7874 m_pWebEm->ClearUserPasswords(); 7875 } 7876 FindUser(const char * szUserName)7877 int CWebServer::FindUser(const char* szUserName) 7878 { 7879 int iUser = 0; 7880 for (const auto & itt : m_users) 7881 { 7882 if (itt.Username == szUserName) 7883 return iUser; 7884 iUser++; 7885 } 7886 return -1; 7887 } 7888 FindAdminUser()7889 bool CWebServer::FindAdminUser() 7890 { 7891 for (const auto & itt : m_users) 7892 { 7893 if (itt.userrights == URIGHTS_ADMIN) 7894 return true; 7895 } 7896 return false; 7897 } 7898 PostSettings(WebEmSession & session,const request & req,reply & rep)7899 void CWebServer::PostSettings(WebEmSession& session, const request& req, reply& rep) 7900 { 7901 if (session.rights != 2) 7902 { 7903 session.reply_status = reply::forbidden; 7904 return; //Only admin user allowed 7905 } 7906 7907 std::string Latitude = request::findValue(&req, "Latitude"); 7908 std::string Longitude = request::findValue(&req, "Longitude"); 7909 if ((Latitude != "") && (Longitude != "")) 7910 { 7911 std::string LatLong = Latitude + ";" + Longitude; 7912 m_sql.UpdatePreferencesVar("Location", LatLong.c_str()); 7913 m_mainworker.GetSunSettings(); 7914 } 7915 m_notifications.ConfigFromGetvars(req, true); 7916 std::string DashboardType = request::findValue(&req, "DashboardType"); 7917 m_sql.UpdatePreferencesVar("DashboardType", atoi(DashboardType.c_str())); 7918 std::string MobileType = request::findValue(&req, "MobileType"); 7919 m_sql.UpdatePreferencesVar("MobileType", atoi(MobileType.c_str())); 7920 7921 int nUnit = atoi(request::findValue(&req, "WindUnit").c_str()); 7922 m_sql.UpdatePreferencesVar("WindUnit", nUnit); 7923 m_sql.m_windunit = (_eWindUnit)nUnit; 7924 7925 nUnit = atoi(request::findValue(&req, "TempUnit").c_str()); 7926 m_sql.UpdatePreferencesVar("TempUnit", nUnit); 7927 m_sql.m_tempunit = (_eTempUnit)nUnit; 7928 7929 nUnit = atoi(request::findValue(&req, "WeightUnit").c_str()); 7930 m_sql.UpdatePreferencesVar("WeightUnit", nUnit); 7931 m_sql.m_weightunit = (_eWeightUnit)nUnit; 7932 7933 7934 m_sql.SetUnitsAndScale(); 7935 7936 std::string AuthenticationMethod = request::findValue(&req, "AuthenticationMethod"); 7937 _eAuthenticationMethod amethod = (_eAuthenticationMethod)atoi(AuthenticationMethod.c_str()); 7938 m_sql.UpdatePreferencesVar("AuthenticationMethod", static_cast<int>(amethod)); 7939 m_pWebEm->SetAuthenticationMethod(amethod); 7940 7941 std::string ReleaseChannel = request::findValue(&req, "ReleaseChannel"); 7942 m_sql.UpdatePreferencesVar("ReleaseChannel", atoi(ReleaseChannel.c_str())); 7943 7944 std::string LightHistoryDays = request::findValue(&req, "LightHistoryDays"); 7945 m_sql.UpdatePreferencesVar("LightHistoryDays", atoi(LightHistoryDays.c_str())); 7946 7947 std::string s5MinuteHistoryDays = request::findValue(&req, "ShortLogDays"); 7948 m_sql.UpdatePreferencesVar("5MinuteHistoryDays", atoi(s5MinuteHistoryDays.c_str())); 7949 7950 int iShortLogInterval = atoi(request::findValue(&req, "ShortLogInterval").c_str()); 7951 if (iShortLogInterval < 1) 7952 iShortLogInterval = 5; 7953 m_sql.UpdatePreferencesVar("ShortLogInterval", iShortLogInterval); 7954 m_sql.m_ShortLogInterval = iShortLogInterval; 7955 7956 std::string sElectricVoltage = request::findValue(&req, "ElectricVoltage"); 7957 m_sql.UpdatePreferencesVar("ElectricVoltage", atoi(sElectricVoltage.c_str())); 7958 7959 std::string sCM113DisplayType = request::findValue(&req, "CM113DisplayType"); 7960 m_sql.UpdatePreferencesVar("CM113DisplayType", atoi(sCM113DisplayType.c_str())); 7961 7962 std::string WebUserName = base64_encode(CURLEncode::URLDecode(request::findValue(&req, "WebUserName"))); 7963 std::string WebPassword = CURLEncode::URLDecode(request::findValue(&req, "WebPassword")); 7964 7965 //Get old username/password 7966 std::string sOldWebLogin; 7967 std::string sOldWebPassword; 7968 m_sql.GetPreferencesVar("WebUserName", sOldWebLogin); 7969 m_sql.GetPreferencesVar("WebPassword", sOldWebPassword); 7970 7971 bool bHaveAdminUserPasswordChange = false; 7972 7973 if ((WebUserName == sOldWebLogin) && (WebPassword.empty())) 7974 { 7975 //All is OK, no changes 7976 } 7977 else if (WebUserName.empty() || WebPassword.empty()) 7978 { 7979 //If no Admin User/Password is specified, we clear them 7980 if ((!sOldWebLogin.empty()) || (!sOldWebPassword.empty())) 7981 bHaveAdminUserPasswordChange = true; 7982 WebUserName = ""; 7983 WebPassword = ""; 7984 } 7985 else { 7986 if ((WebUserName != sOldWebLogin) || (WebPassword != sOldWebPassword)) 7987 { 7988 bHaveAdminUserPasswordChange = true; 7989 } 7990 } 7991 7992 // Invalid sessions of WebUser when the username or password has been changed 7993 if (bHaveAdminUserPasswordChange) 7994 { 7995 RemoveUsersSessions(sOldWebLogin, session); 7996 m_sql.UpdatePreferencesVar("WebUserName", WebUserName.c_str()); 7997 m_sql.UpdatePreferencesVar("WebPassword", WebPassword.c_str()); 7998 } 7999 8000 std::string WebLocalNetworks = CURLEncode::URLDecode(request::findValue(&req, "WebLocalNetworks")); 8001 std::string WebRemoteProxyIPs = CURLEncode::URLDecode(request::findValue(&req, "WebRemoteProxyIPs")); 8002 m_sql.UpdatePreferencesVar("WebLocalNetworks", WebLocalNetworks.c_str()); 8003 m_sql.UpdatePreferencesVar("WebRemoteProxyIPs", WebRemoteProxyIPs.c_str()); 8004 8005 LoadUsers(); 8006 m_pWebEm->ClearLocalNetworks(); 8007 std::vector<std::string> strarray; 8008 StringSplit(WebLocalNetworks, ";", strarray); 8009 for (const auto & itt : strarray) 8010 m_pWebEm->AddLocalNetworks(itt); 8011 //add local hostname 8012 m_pWebEm->AddLocalNetworks(""); 8013 8014 m_pWebEm->ClearRemoteProxyIPs(); 8015 strarray.clear(); 8016 StringSplit(WebRemoteProxyIPs, ";", strarray); 8017 for (const auto & itt : strarray) 8018 m_pWebEm->AddRemoteProxyIPs(itt); 8019 8020 if (session.username.empty()) 8021 { 8022 //Local network could be changed so lets for a check here 8023 session.rights = -1; 8024 } 8025 8026 std::string SecPassword = request::findValue(&req, "SecPassword"); 8027 SecPassword = CURLEncode::URLDecode(SecPassword); 8028 if (SecPassword.size() != 32) 8029 { 8030 SecPassword = GenerateMD5Hash(SecPassword); 8031 } 8032 m_sql.UpdatePreferencesVar("SecPassword", SecPassword.c_str()); 8033 8034 std::string ProtectionPassword = request::findValue(&req, "ProtectionPassword"); 8035 ProtectionPassword = CURLEncode::URLDecode(ProtectionPassword); 8036 if (ProtectionPassword.size() != 32) 8037 { 8038 ProtectionPassword = GenerateMD5Hash(ProtectionPassword); 8039 } 8040 m_sql.UpdatePreferencesVar("ProtectionPassword", ProtectionPassword.c_str()); 8041 8042 int EnergyDivider = atoi(request::findValue(&req, "EnergyDivider").c_str()); 8043 int GasDivider = atoi(request::findValue(&req, "GasDivider").c_str()); 8044 int WaterDivider = atoi(request::findValue(&req, "WaterDivider").c_str()); 8045 if (EnergyDivider < 1) 8046 EnergyDivider = 1000; 8047 if (GasDivider < 1) 8048 GasDivider = 100; 8049 if (WaterDivider < 1) 8050 WaterDivider = 100; 8051 m_sql.UpdatePreferencesVar("MeterDividerEnergy", EnergyDivider); 8052 m_sql.UpdatePreferencesVar("MeterDividerGas", GasDivider); 8053 m_sql.UpdatePreferencesVar("MeterDividerWater", WaterDivider); 8054 8055 std::string scheckforupdates = request::findValue(&req, "checkforupdates"); 8056 m_sql.UpdatePreferencesVar("UseAutoUpdate", (scheckforupdates == "on" ? 1 : 0)); 8057 8058 std::string senableautobackup = request::findValue(&req, "enableautobackup"); 8059 m_sql.UpdatePreferencesVar("UseAutoBackup", (senableautobackup == "on" ? 1 : 0)); 8060 8061 float CostEnergy = static_cast<float>(atof(request::findValue(&req, "CostEnergy").c_str())); 8062 float CostEnergyT2 = static_cast<float>(atof(request::findValue(&req, "CostEnergyT2").c_str())); 8063 float CostEnergyR1 = static_cast<float>(atof(request::findValue(&req, "CostEnergyR1").c_str())); 8064 float CostEnergyR2 = static_cast<float>(atof(request::findValue(&req, "CostEnergyR2").c_str())); 8065 float CostGas = static_cast<float>(atof(request::findValue(&req, "CostGas").c_str())); 8066 float CostWater = static_cast<float>(atof(request::findValue(&req, "CostWater").c_str())); 8067 m_sql.UpdatePreferencesVar("CostEnergy", int(CostEnergy*10000.0f)); 8068 m_sql.UpdatePreferencesVar("CostEnergyT2", int(CostEnergyT2*10000.0f)); 8069 m_sql.UpdatePreferencesVar("CostEnergyR1", int(CostEnergyR1*10000.0f)); 8070 m_sql.UpdatePreferencesVar("CostEnergyR2", int(CostEnergyR2*10000.0f)); 8071 m_sql.UpdatePreferencesVar("CostGas", int(CostGas*10000.0f)); 8072 m_sql.UpdatePreferencesVar("CostWater", int(CostWater*10000.0f)); 8073 8074 int rnOldvalue = 0; 8075 int rnvalue = 0; 8076 8077 m_sql.GetPreferencesVar("ActiveTimerPlan", rnOldvalue); 8078 rnvalue = atoi(request::findValue(&req, "ActiveTimerPlan").c_str()); 8079 if (rnOldvalue != rnvalue) 8080 { 8081 m_sql.UpdatePreferencesVar("ActiveTimerPlan", rnvalue); 8082 m_sql.m_ActiveTimerPlan = rnvalue; 8083 m_mainworker.m_scheduler.ReloadSchedules(); 8084 } 8085 m_sql.UpdatePreferencesVar("DoorbellCommand", atoi(request::findValue(&req, "DoorbellCommand").c_str())); 8086 m_sql.UpdatePreferencesVar("SmartMeterType", atoi(request::findValue(&req, "SmartMeterType").c_str())); 8087 8088 std::string EnableTabFloorplans = request::findValue(&req, "EnableTabFloorplans"); 8089 m_sql.UpdatePreferencesVar("EnableTabFloorplans", (EnableTabFloorplans == "on" ? 1 : 0)); 8090 std::string EnableTabLights = request::findValue(&req, "EnableTabLights"); 8091 m_sql.UpdatePreferencesVar("EnableTabLights", (EnableTabLights == "on" ? 1 : 0)); 8092 std::string EnableTabTemp = request::findValue(&req, "EnableTabTemp"); 8093 m_sql.UpdatePreferencesVar("EnableTabTemp", (EnableTabTemp == "on" ? 1 : 0)); 8094 std::string EnableTabWeather = request::findValue(&req, "EnableTabWeather"); 8095 m_sql.UpdatePreferencesVar("EnableTabWeather", (EnableTabWeather == "on" ? 1 : 0)); 8096 std::string EnableTabUtility = request::findValue(&req, "EnableTabUtility"); 8097 m_sql.UpdatePreferencesVar("EnableTabUtility", (EnableTabUtility == "on" ? 1 : 0)); 8098 std::string EnableTabScenes = request::findValue(&req, "EnableTabScenes"); 8099 m_sql.UpdatePreferencesVar("EnableTabScenes", (EnableTabScenes == "on" ? 1 : 0)); 8100 std::string EnableTabCustom = request::findValue(&req, "EnableTabCustom"); 8101 m_sql.UpdatePreferencesVar("EnableTabCustom", (EnableTabCustom == "on" ? 1 : 0)); 8102 8103 m_sql.GetPreferencesVar("NotificationSensorInterval", rnOldvalue); 8104 rnvalue = atoi(request::findValue(&req, "NotificationSensorInterval").c_str()); 8105 if (rnOldvalue != rnvalue) 8106 { 8107 m_sql.UpdatePreferencesVar("NotificationSensorInterval", rnvalue); 8108 m_notifications.ReloadNotifications(); 8109 } 8110 m_sql.GetPreferencesVar("NotificationSwitchInterval", rnOldvalue); 8111 rnvalue = atoi(request::findValue(&req, "NotificationSwitchInterval").c_str()); 8112 if (rnOldvalue != rnvalue) 8113 { 8114 m_sql.UpdatePreferencesVar("NotificationSwitchInterval", rnvalue); 8115 m_notifications.ReloadNotifications(); 8116 } 8117 std::string RaspCamParams = request::findValue(&req, "RaspCamParams"); 8118 if (RaspCamParams != "") 8119 { 8120 if (IsArgumentSecure(RaspCamParams)) 8121 m_sql.UpdatePreferencesVar("RaspCamParams", RaspCamParams.c_str()); 8122 } 8123 8124 std::string UVCParams = request::findValue(&req, "UVCParams"); 8125 if (UVCParams != "") 8126 { 8127 if (IsArgumentSecure(UVCParams)) 8128 m_sql.UpdatePreferencesVar("UVCParams", UVCParams.c_str()); 8129 } 8130 8131 std::string EnableNewHardware = request::findValue(&req, "AcceptNewHardware"); 8132 int iEnableNewHardware = (EnableNewHardware == "on" ? 1 : 0); 8133 m_sql.UpdatePreferencesVar("AcceptNewHardware", iEnableNewHardware); 8134 m_sql.m_bAcceptNewHardware = (iEnableNewHardware == 1); 8135 8136 std::string HideDisabledHardwareSensors = request::findValue(&req, "HideDisabledHardwareSensors"); 8137 int iHideDisabledHardwareSensors = (HideDisabledHardwareSensors == "on" ? 1 : 0); 8138 m_sql.UpdatePreferencesVar("HideDisabledHardwareSensors", iHideDisabledHardwareSensors); 8139 8140 std::string ShowUpdateEffect = request::findValue(&req, "ShowUpdateEffect"); 8141 int iShowUpdateEffect = (ShowUpdateEffect == "on" ? 1 : 0); 8142 m_sql.UpdatePreferencesVar("ShowUpdateEffect", iShowUpdateEffect); 8143 8144 std::string SendErrorsAsNotification = request::findValue(&req, "SendErrorsAsNotification"); 8145 int iSendErrorsAsNotification = (SendErrorsAsNotification == "on" ? 1 : 0); 8146 m_sql.UpdatePreferencesVar("SendErrorsAsNotification", iSendErrorsAsNotification); 8147 _log.ForwardErrorsToNotificationSystem(iSendErrorsAsNotification != 0); 8148 8149 std::string DegreeDaysBaseTemperature = request::findValue(&req, "DegreeDaysBaseTemperature"); 8150 m_sql.UpdatePreferencesVar("DegreeDaysBaseTemperature", DegreeDaysBaseTemperature); 8151 8152 rnOldvalue = 0; 8153 m_sql.GetPreferencesVar("EnableEventScriptSystem", rnOldvalue); 8154 std::string EnableEventScriptSystem = request::findValue(&req, "EnableEventScriptSystem"); 8155 int iEnableEventScriptSystem = (EnableEventScriptSystem == "on" ? 1 : 0); 8156 m_sql.UpdatePreferencesVar("EnableEventScriptSystem", iEnableEventScriptSystem); 8157 m_sql.m_bEnableEventSystem = (iEnableEventScriptSystem == 1); 8158 if (iEnableEventScriptSystem != rnOldvalue) 8159 { 8160 m_mainworker.m_eventsystem.SetEnabled(m_sql.m_bEnableEventSystem); 8161 m_mainworker.m_eventsystem.StartEventSystem(); 8162 } 8163 std::string EnableEventSystemFullURLLog = request::findValue(&req, "EventSystemLogFullURL"); 8164 m_sql.m_bEnableEventSystemFullURLLog = EnableEventSystemFullURLLog == "on" ? true : false; 8165 m_sql.UpdatePreferencesVar("EventSystemLogFullURL", (int)m_sql.m_bEnableEventSystemFullURLLog); 8166 8167 rnOldvalue = 0; 8168 m_sql.GetPreferencesVar("DisableDzVentsSystem", rnOldvalue); 8169 std::string DisableDzVentsSystem = request::findValue(&req, "DisableDzVentsSystem"); 8170 int iDisableDzVentsSystem = (DisableDzVentsSystem == "on" ? 0 : 1); 8171 m_sql.UpdatePreferencesVar("DisableDzVentsSystem", iDisableDzVentsSystem); 8172 m_sql.m_bDisableDzVentsSystem = (iDisableDzVentsSystem == 1); 8173 if (m_sql.m_bEnableEventSystem && !iDisableDzVentsSystem && iDisableDzVentsSystem != rnOldvalue) 8174 { 8175 m_mainworker.m_eventsystem.LoadEvents(); 8176 m_mainworker.m_eventsystem.GetCurrentStates(); 8177 } 8178 m_sql.UpdatePreferencesVar("DzVentsLogLevel", atoi(request::findValue(&req, "DzVentsLogLevel").c_str())); 8179 8180 std::string LogEventScriptTrigger = request::findValue(&req, "LogEventScriptTrigger"); 8181 m_sql.m_bLogEventScriptTrigger = (LogEventScriptTrigger == "on" ? 1 : 0); 8182 m_sql.UpdatePreferencesVar("LogEventScriptTrigger", m_sql.m_bLogEventScriptTrigger); 8183 8184 std::string EnableWidgetOrdering = request::findValue(&req, "AllowWidgetOrdering"); 8185 int iEnableAllowWidgetOrdering = (EnableWidgetOrdering == "on" ? 1 : 0); 8186 m_sql.UpdatePreferencesVar("AllowWidgetOrdering", iEnableAllowWidgetOrdering); 8187 m_sql.m_bAllowWidgetOrdering = (iEnableAllowWidgetOrdering == 1); 8188 8189 rnOldvalue = 0; 8190 m_sql.GetPreferencesVar("RemoteSharedPort", rnOldvalue); 8191 8192 m_sql.UpdatePreferencesVar("RemoteSharedPort", atoi(request::findValue(&req, "RemoteSharedPort").c_str())); 8193 8194 rnvalue = 0; 8195 m_sql.GetPreferencesVar("RemoteSharedPort", rnvalue); 8196 8197 if (rnvalue != rnOldvalue) 8198 { 8199 m_mainworker.m_sharedserver.StopServer(); 8200 if (rnvalue != 0) 8201 { 8202 char szPort[100]; 8203 sprintf(szPort, "%d", rnvalue); 8204 m_mainworker.m_sharedserver.StartServer("::", szPort); 8205 m_mainworker.LoadSharedUsers(); 8206 } 8207 } 8208 8209 m_sql.UpdatePreferencesVar("Language", request::findValue(&req, "Language").c_str()); 8210 std::string SelectedTheme = request::findValue(&req, "Themes"); 8211 m_sql.UpdatePreferencesVar("WebTheme", SelectedTheme.c_str()); 8212 m_pWebEm->SetWebTheme(SelectedTheme); 8213 std::string Title = request::findValue(&req, "Title").c_str(); 8214 m_sql.UpdatePreferencesVar("Title", (Title.empty()) ? "Domoticz" : Title); 8215 8216 m_sql.GetPreferencesVar("RandomTimerFrame", rnOldvalue); 8217 rnvalue = atoi(request::findValue(&req, "RandomSpread").c_str()); 8218 if (rnOldvalue != rnvalue) 8219 { 8220 m_sql.UpdatePreferencesVar("RandomTimerFrame", rnvalue); 8221 m_mainworker.m_scheduler.ReloadSchedules(); 8222 } 8223 8224 m_sql.UpdatePreferencesVar("SecOnDelay", atoi(request::findValue(&req, "SecOnDelay").c_str())); 8225 8226 int sensortimeout = atoi(request::findValue(&req, "SensorTimeout").c_str()); 8227 if (sensortimeout < 10) 8228 sensortimeout = 10; 8229 m_sql.UpdatePreferencesVar("SensorTimeout", sensortimeout); 8230 8231 int batterylowlevel = atoi(request::findValue(&req, "BatterLowLevel").c_str()); 8232 if (batterylowlevel > 100) 8233 batterylowlevel = 100; 8234 m_sql.GetPreferencesVar("BatteryLowNotification", rnOldvalue); 8235 m_sql.UpdatePreferencesVar("BatteryLowNotification", batterylowlevel); 8236 if ((rnOldvalue != batterylowlevel) && (batterylowlevel != 0)) 8237 m_sql.CheckBatteryLow(); 8238 8239 int nValue = 0; 8240 nValue = atoi(request::findValue(&req, "FloorplanPopupDelay").c_str()); 8241 m_sql.UpdatePreferencesVar("FloorplanPopupDelay", nValue); 8242 std::string FloorplanFullscreenMode = request::findValue(&req, "FloorplanFullscreenMode"); 8243 m_sql.UpdatePreferencesVar("FloorplanFullscreenMode", (FloorplanFullscreenMode == "on" ? 1 : 0)); 8244 std::string FloorplanAnimateZoom = request::findValue(&req, "FloorplanAnimateZoom"); 8245 m_sql.UpdatePreferencesVar("FloorplanAnimateZoom", (FloorplanAnimateZoom == "on" ? 1 : 0)); 8246 std::string FloorplanShowSensorValues = request::findValue(&req, "FloorplanShowSensorValues"); 8247 m_sql.UpdatePreferencesVar("FloorplanShowSensorValues", (FloorplanShowSensorValues == "on" ? 1 : 0)); 8248 std::string FloorplanShowSwitchValues = request::findValue(&req, "FloorplanShowSwitchValues"); 8249 m_sql.UpdatePreferencesVar("FloorplanShowSwitchValues", (FloorplanShowSwitchValues == "on" ? 1 : 0)); 8250 std::string FloorplanShowSceneNames = request::findValue(&req, "FloorplanShowSceneNames"); 8251 m_sql.UpdatePreferencesVar("FloorplanShowSceneNames", (FloorplanShowSceneNames == "on" ? 1 : 0)); 8252 m_sql.UpdatePreferencesVar("FloorplanRoomColour", CURLEncode::URLDecode(request::findValue(&req, "FloorplanRoomColour").c_str()).c_str()); 8253 m_sql.UpdatePreferencesVar("FloorplanActiveOpacity", atoi(request::findValue(&req, "FloorplanActiveOpacity").c_str())); 8254 m_sql.UpdatePreferencesVar("FloorplanInactiveOpacity", atoi(request::findValue(&req, "FloorplanInactiveOpacity").c_str())); 8255 8256 #ifndef NOCLOUD 8257 std::string md_userid, md_password, pf_userid, pf_password; 8258 int md_subsystems, pf_subsystems; 8259 m_sql.GetPreferencesVar("MyDomoticzUserId", pf_userid); 8260 m_sql.GetPreferencesVar("MyDomoticzPassword", pf_password); 8261 m_sql.GetPreferencesVar("MyDomoticzSubsystems", pf_subsystems); 8262 md_userid = CURLEncode::URLDecode(request::findValue(&req, "MyDomoticzUserId")); 8263 md_password = CURLEncode::URLDecode(request::findValue(&req, "MyDomoticzPassword")); 8264 md_subsystems = (request::findValue(&req, "SubsystemHttp").empty() ? 0 : 1) + (request::findValue(&req, "SubsystemShared").empty() ? 0 : 2) + (request::findValue(&req, "SubsystemApps").empty() ? 0 : 4); 8265 if (md_userid != pf_userid || md_password != pf_password || md_subsystems != pf_subsystems) { 8266 m_sql.UpdatePreferencesVar("MyDomoticzUserId", md_userid); 8267 if (md_password != pf_password) { 8268 md_password = base64_encode(md_password); 8269 m_sql.UpdatePreferencesVar("MyDomoticzPassword", md_password); 8270 } 8271 m_sql.UpdatePreferencesVar("MyDomoticzSubsystems", md_subsystems); 8272 m_webservers.RestartProxy(); 8273 } 8274 #endif 8275 8276 m_sql.UpdatePreferencesVar("OneWireSensorPollPeriod", atoi(request::findValue(&req, "OneWireSensorPollPeriod").c_str())); 8277 m_sql.UpdatePreferencesVar("OneWireSwitchPollPeriod", atoi(request::findValue(&req, "OneWireSwitchPollPeriod").c_str())); 8278 8279 std::string IFTTTEnabled = request::findValue(&req, "IFTTTEnabled"); 8280 int iIFTTTEnabled = (IFTTTEnabled == "on" ? 1 : 0); 8281 m_sql.UpdatePreferencesVar("IFTTTEnabled", iIFTTTEnabled); 8282 std::string szKey = request::findValue(&req, "IFTTTAPI"); 8283 m_sql.UpdatePreferencesVar("IFTTTAPI", base64_encode(szKey)); 8284 8285 m_notifications.LoadConfig(); 8286 #ifdef ENABLE_PYTHON 8287 //Signal plugins to update Settings dictionary 8288 PluginLoadConfig(); 8289 #endif 8290 8291 Json::Value root; 8292 root["status"] = "OK"; 8293 root["title"] = "StoreSettings"; 8294 8295 std::string jcallback = request::findValue(&req, "jsoncallback"); 8296 if (jcallback.size() == 0) { 8297 reply::set_content(&rep, root.toStyledString()); 8298 return; 8299 } 8300 reply::set_content(&rep, "var data=" + root.toStyledString() + '\n' + jcallback + "(data);"); 8301 8302 } 8303 RestoreDatabase(WebEmSession & session,const request & req,std::string & redirect_uri)8304 void CWebServer::RestoreDatabase(WebEmSession & session, const request& req, std::string & redirect_uri) 8305 { 8306 redirect_uri = "/index.html"; 8307 if (session.rights != 2) 8308 { 8309 session.reply_status = reply::forbidden; 8310 return; //Only admin user allowed 8311 } 8312 8313 std::string dbasefile = request::findValue(&req, "dbasefile"); 8314 if (dbasefile.empty()) { 8315 return; 8316 } 8317 8318 m_mainworker.StopDomoticzHardware(); 8319 8320 m_sql.RestoreDatabase(dbasefile); 8321 m_mainworker.AddAllDomoticzHardware(); 8322 } 8323 8324 struct _tHardwareListInt { 8325 std::string Name; 8326 int HardwareTypeVal; 8327 std::string HardwareType; 8328 bool Enabled; 8329 std::string Mode1; // Used to flag DimmerType as relative for some old LimitLessLight type bulbs 8330 std::string Mode2; // Used to flag DimmerType as relative for some old LimitLessLight type bulbs 8331 } tHardwareList; 8332 GetJSonDevices(Json::Value & root,const std::string & rused,const std::string & rfilter,const std::string & order,const std::string & rowid,const std::string & planID,const std::string & floorID,const bool bDisplayHidden,const bool bDisplayDisabled,const bool bFetchFavorites,const time_t LastUpdate,const std::string & username,const std::string & hardwareid)8333 void CWebServer::GetJSonDevices( 8334 Json::Value &root, 8335 const std::string &rused, 8336 const std::string &rfilter, 8337 const std::string &order, 8338 const std::string &rowid, 8339 const std::string &planID, 8340 const std::string &floorID, 8341 const bool bDisplayHidden, 8342 const bool bDisplayDisabled, 8343 const bool bFetchFavorites, 8344 const time_t LastUpdate, 8345 const std::string &username, 8346 const std::string &hardwareid) 8347 { 8348 std::vector<std::vector<std::string> > result; 8349 8350 time_t now = mytime(NULL); 8351 struct tm tm1; 8352 localtime_r(&now, &tm1); 8353 struct tm tLastUpdate; 8354 localtime_r(&now, &tLastUpdate); 8355 8356 const time_t iLastUpdate = LastUpdate - 1; 8357 8358 int SensorTimeOut = 60; 8359 m_sql.GetPreferencesVar("SensorTimeout", SensorTimeOut); 8360 8361 //Get All Hardware ID's/Names, need them later 8362 std::map<int, _tHardwareListInt> _hardwareNames; 8363 result = m_sql.safe_query("SELECT ID, Name, Enabled, Type, Mode1, Mode2 FROM Hardware"); 8364 if (!result.empty()) 8365 { 8366 for (const auto & itt : result) 8367 { 8368 std::vector<std::string> sd = itt; 8369 _tHardwareListInt tlist; 8370 int ID = atoi(sd[0].c_str()); 8371 tlist.Name = sd[1]; 8372 tlist.Enabled = (atoi(sd[2].c_str()) != 0); 8373 tlist.HardwareTypeVal = atoi(sd[3].c_str()); 8374 #ifndef ENABLE_PYTHON 8375 tlist.HardwareType = Hardware_Type_Desc(tlist.HardwareTypeVal); 8376 #else 8377 if (tlist.HardwareTypeVal != HTYPE_PythonPlugin) 8378 { 8379 tlist.HardwareType = Hardware_Type_Desc(tlist.HardwareTypeVal); 8380 } 8381 else 8382 { 8383 tlist.HardwareType = PluginHardwareDesc(ID); 8384 } 8385 #endif 8386 tlist.Mode1 = sd[4]; 8387 tlist.Mode2 = sd[5]; 8388 _hardwareNames[ID] = tlist; 8389 } 8390 } 8391 8392 root["ActTime"] = static_cast<int>(now); 8393 8394 char szTmp[300]; 8395 8396 if (!m_mainworker.m_LastSunriseSet.empty()) 8397 { 8398 std::vector<std::string> strarray; 8399 StringSplit(m_mainworker.m_LastSunriseSet, ";", strarray); 8400 if (strarray.size() == 10) 8401 { 8402 //strftime(szTmp, 80, "%b %d %Y %X", &tm1); 8403 strftime(szTmp, 80, "%Y-%m-%d %X", &tm1); 8404 root["ServerTime"] = szTmp; 8405 root["Sunrise"] = strarray[0]; 8406 root["Sunset"] = strarray[1]; 8407 root["SunAtSouth"] = strarray[2]; 8408 root["CivTwilightStart"] = strarray[3]; 8409 root["CivTwilightEnd"] = strarray[4]; 8410 root["NautTwilightStart"] = strarray[5]; 8411 root["NautTwilightEnd"] = strarray[6]; 8412 root["AstrTwilightStart"] = strarray[7]; 8413 root["AstrTwilightEnd"] = strarray[8]; 8414 root["DayLength"] = strarray[9]; 8415 } 8416 } 8417 8418 char szOrderBy[50]; 8419 std::string szQuery; 8420 bool isAlpha = true; 8421 const std::string orderBy = order.c_str(); 8422 for (size_t i = 0; i < orderBy.size(); i++) { 8423 if (!isalpha(orderBy[i])) { 8424 isAlpha = false; 8425 } 8426 } 8427 if (order.empty() || (!isAlpha)) { 8428 strcpy(szOrderBy, "A.[Order],A.LastUpdate DESC"); 8429 } else { 8430 sprintf(szOrderBy, "A.[Order],A.%%s ASC"); 8431 } 8432 8433 unsigned char tempsign = m_sql.m_tempsign[0]; 8434 8435 bool bHaveUser = false; 8436 int iUser = -1; 8437 unsigned int totUserDevices = 0; 8438 bool bShowScenes = true; 8439 bHaveUser = (username != ""); 8440 if (bHaveUser) 8441 { 8442 iUser = FindUser(username.c_str()); 8443 if (iUser != -1) 8444 { 8445 _eUserRights urights = m_users[iUser].userrights; 8446 if (urights != URIGHTS_ADMIN) 8447 { 8448 result = m_sql.safe_query("SELECT COUNT(*) FROM SharedDevices WHERE (SharedUserID == %lu)", m_users[iUser].ID); 8449 if (!result.empty()) 8450 { 8451 totUserDevices = (unsigned int)std::stoi(result[0][0]); 8452 } 8453 bShowScenes = (m_users[iUser].ActiveTabs&(1 << 1)) != 0; 8454 } 8455 } 8456 } 8457 8458 std::set<std::string> _HiddenDevices; 8459 bool bAllowDeviceToBeHidden = false; 8460 8461 int ii = 0; 8462 if (rfilter == "all") 8463 { 8464 if ( 8465 (bShowScenes) && 8466 ((rused == "all") || (rused == "true")) 8467 ) 8468 { 8469 //add scenes 8470 if (rowid != "") 8471 result = m_sql.safe_query( 8472 "SELECT A.ID, A.Name, A.nValue, A.LastUpdate, A.Favorite, A.SceneType," 8473 " A.Protected, B.XOffset, B.YOffset, B.PlanID, A.Description" 8474 " FROM Scenes as A" 8475 " LEFT OUTER JOIN DeviceToPlansMap as B ON (B.DeviceRowID==a.ID) AND (B.DevSceneType==1)" 8476 " WHERE (A.ID=='%q')", 8477 rowid.c_str()); 8478 else if ((planID != "") && (planID != "0")) 8479 result = m_sql.safe_query( 8480 "SELECT A.ID, A.Name, A.nValue, A.LastUpdate, A.Favorite, A.SceneType," 8481 " A.Protected, B.XOffset, B.YOffset, B.PlanID, A.Description" 8482 " FROM Scenes as A, DeviceToPlansMap as B WHERE (B.PlanID=='%q')" 8483 " AND (B.DeviceRowID==a.ID) AND (B.DevSceneType==1) ORDER BY B.[Order]", 8484 planID.c_str()); 8485 else if ((floorID != "") && (floorID != "0")) 8486 result = m_sql.safe_query( 8487 "SELECT A.ID, A.Name, A.nValue, A.LastUpdate, A.Favorite, A.SceneType," 8488 " A.Protected, B.XOffset, B.YOffset, B.PlanID, A.Description" 8489 " FROM Scenes as A, DeviceToPlansMap as B, Plans as C" 8490 " WHERE (C.FloorplanID=='%q') AND (C.ID==B.PlanID) AND (B.DeviceRowID==a.ID)" 8491 " AND (B.DevSceneType==1) ORDER BY B.[Order]", 8492 floorID.c_str()); 8493 else { 8494 szQuery = ( 8495 "SELECT A.ID, A.Name, A.nValue, A.LastUpdate, A.Favorite, A.SceneType," 8496 " A.Protected, B.XOffset, B.YOffset, B.PlanID, A.Description" 8497 " FROM Scenes as A" 8498 " LEFT OUTER JOIN DeviceToPlansMap as B ON (B.DeviceRowID==a.ID) AND (B.DevSceneType==1)" 8499 " ORDER BY "); 8500 szQuery += szOrderBy; 8501 result = m_sql.safe_query(szQuery.c_str(), order.c_str()); 8502 } 8503 8504 if (!result.empty()) 8505 { 8506 for (const auto & itt : result) 8507 { 8508 std::vector<std::string> sd = itt; 8509 8510 unsigned char favorite = atoi(sd[4].c_str()); 8511 //Check if we only want favorite devices 8512 if ((bFetchFavorites) && (!favorite)) 8513 continue; 8514 8515 std::string sLastUpdate = sd[3]; 8516 8517 if (iLastUpdate != 0) 8518 { 8519 time_t cLastUpdate; 8520 ParseSQLdatetime(cLastUpdate, tLastUpdate, sLastUpdate, tm1.tm_isdst); 8521 if (cLastUpdate <= iLastUpdate) 8522 continue; 8523 } 8524 8525 int nValue = atoi(sd[2].c_str()); 8526 8527 unsigned char scenetype = atoi(sd[5].c_str()); 8528 int iProtected = atoi(sd[6].c_str()); 8529 8530 std::string sSceneName = sd[1]; 8531 if (!bDisplayHidden && sSceneName[0] == '$') 8532 { 8533 continue; 8534 } 8535 8536 if (scenetype == 0) 8537 { 8538 root["result"][ii]["Type"] = "Scene"; 8539 root["result"][ii]["TypeImg"] = "scene"; 8540 root["result"][ii]["Image"] = "Push"; 8541 } 8542 else 8543 { 8544 root["result"][ii]["Type"] = "Group"; 8545 root["result"][ii]["TypeImg"] = "group"; 8546 } 8547 8548 // has this scene/group already been seen, now with different plan? 8549 // assume results are ordered such that same device is adjacent 8550 // if the idx and the Type are equal (type to prevent matching against Scene with same idx) 8551 std::string thisIdx = sd[0]; 8552 8553 if ((ii > 0) && thisIdx == root["result"][ii - 1]["idx"].asString()) { 8554 std::string typeOfThisOne = root["result"][ii]["Type"].asString(); 8555 if (typeOfThisOne == root["result"][ii - 1]["Type"].asString()) { 8556 root["result"][ii - 1]["PlanIDs"].append(atoi(sd[9].c_str())); 8557 continue; 8558 } 8559 } 8560 8561 root["result"][ii]["idx"] = sd[0]; 8562 root["result"][ii]["Name"] = sSceneName; 8563 root["result"][ii]["Description"] = sd[10]; 8564 root["result"][ii]["Favorite"] = favorite; 8565 root["result"][ii]["Protected"] = (iProtected != 0); 8566 root["result"][ii]["LastUpdate"] = sLastUpdate; 8567 root["result"][ii]["PlanID"] = sd[9].c_str(); 8568 Json::Value jsonArray; 8569 jsonArray.append(atoi(sd[9].c_str())); 8570 root["result"][ii]["PlanIDs"] = jsonArray; 8571 8572 if (nValue == 0) 8573 root["result"][ii]["Status"] = "Off"; 8574 else if (nValue == 1) 8575 root["result"][ii]["Status"] = "On"; 8576 else 8577 root["result"][ii]["Status"] = "Mixed"; 8578 root["result"][ii]["Data"] = root["result"][ii]["Status"]; 8579 uint64_t camIDX = m_mainworker.m_cameras.IsDevSceneInCamera(1, sd[0]); 8580 root["result"][ii]["UsedByCamera"] = (camIDX != 0) ? true : false; 8581 if (camIDX != 0) { 8582 std::stringstream scidx; 8583 scidx << camIDX; 8584 root["result"][ii]["CameraIdx"] = scidx.str(); 8585 } 8586 root["result"][ii]["XOffset"] = atoi(sd[7].c_str()); 8587 root["result"][ii]["YOffset"] = atoi(sd[8].c_str()); 8588 ii++; 8589 } 8590 } 8591 } 8592 } 8593 8594 char szData[320]; 8595 if (totUserDevices == 0) 8596 { 8597 //All 8598 if (rowid != "") 8599 { 8600 //_log.Log(LOG_STATUS, "Getting device with id: %s", rowid.c_str()); 8601 result = m_sql.safe_query( 8602 "SELECT A.ID, A.DeviceID, A.Unit, A.Name, A.Used, A.Type, A.SubType," 8603 " A.SignalLevel, A.BatteryLevel, A.nValue, A.sValue," 8604 " A.LastUpdate, A.Favorite, A.SwitchType, A.HardwareID," 8605 " A.AddjValue, A.AddjMulti, A.AddjValue2, A.AddjMulti2," 8606 " A.LastLevel, A.CustomImage, A.StrParam1, A.StrParam2," 8607 " A.Protected, IFNULL(B.XOffset,0), IFNULL(B.YOffset,0), IFNULL(B.PlanID,0), A.Description," 8608 " A.Options, A.Color " 8609 "FROM DeviceStatus A LEFT OUTER JOIN DeviceToPlansMap as B ON (B.DeviceRowID==a.ID) " 8610 "WHERE (A.ID=='%q')", 8611 rowid.c_str()); 8612 } 8613 else if ((planID != "") && (planID != "0")) 8614 result = m_sql.safe_query( 8615 "SELECT A.ID, A.DeviceID, A.Unit, A.Name, A.Used," 8616 " A.Type, A.SubType, A.SignalLevel, A.BatteryLevel," 8617 " A.nValue, A.sValue, A.LastUpdate, A.Favorite," 8618 " A.SwitchType, A.HardwareID, A.AddjValue," 8619 " A.AddjMulti, A.AddjValue2, A.AddjMulti2," 8620 " A.LastLevel, A.CustomImage, A.StrParam1," 8621 " A.StrParam2, A.Protected, B.XOffset, B.YOffset," 8622 " B.PlanID, A.Description," 8623 " A.Options, A.Color " 8624 "FROM DeviceStatus as A, DeviceToPlansMap as B " 8625 "WHERE (B.PlanID=='%q') AND (B.DeviceRowID==a.ID)" 8626 " AND (B.DevSceneType==0) ORDER BY B.[Order]", 8627 planID.c_str()); 8628 else if ((floorID != "") && (floorID != "0")) 8629 result = m_sql.safe_query( 8630 "SELECT A.ID, A.DeviceID, A.Unit, A.Name, A.Used," 8631 " A.Type, A.SubType, A.SignalLevel, A.BatteryLevel," 8632 " A.nValue, A.sValue, A.LastUpdate, A.Favorite," 8633 " A.SwitchType, A.HardwareID, A.AddjValue," 8634 " A.AddjMulti, A.AddjValue2, A.AddjMulti2," 8635 " A.LastLevel, A.CustomImage, A.StrParam1," 8636 " A.StrParam2, A.Protected, B.XOffset, B.YOffset," 8637 " B.PlanID, A.Description," 8638 " A.Options, A.Color " 8639 "FROM DeviceStatus as A, DeviceToPlansMap as B," 8640 " Plans as C " 8641 "WHERE (C.FloorplanID=='%q') AND (C.ID==B.PlanID)" 8642 " AND (B.DeviceRowID==a.ID) AND (B.DevSceneType==0) " 8643 "ORDER BY B.[Order]", 8644 floorID.c_str()); 8645 else { 8646 if (!bDisplayHidden) 8647 { 8648 //Build a list of Hidden Devices 8649 result = m_sql.safe_query("SELECT ID FROM Plans WHERE (Name=='$Hidden Devices')"); 8650 if (!result.empty()) 8651 { 8652 std::string pID = result[0][0]; 8653 result = m_sql.safe_query("SELECT DeviceRowID FROM DeviceToPlansMap WHERE (PlanID=='%q') AND (DevSceneType==0)", 8654 pID.c_str()); 8655 if (!result.empty()) 8656 { 8657 std::vector<std::vector<std::string> >::const_iterator ittP; 8658 for (ittP = result.begin(); ittP != result.end(); ++ittP) 8659 { 8660 _HiddenDevices.insert(ittP[0][0]); 8661 } 8662 } 8663 } 8664 bAllowDeviceToBeHidden = true; 8665 } 8666 8667 if (order.empty() || (!isAlpha)) 8668 strcpy(szOrderBy, "A.[Order],A.LastUpdate DESC"); 8669 else 8670 { 8671 sprintf(szOrderBy, "A.[Order],A.%%s ASC"); 8672 } 8673 //_log.Log(LOG_STATUS, "Getting all devices: order by %s ", szOrderBy); 8674 if (hardwareid != "") { 8675 szQuery = ( 8676 "SELECT A.ID, A.DeviceID, A.Unit, A.Name, A.Used,A.Type, A.SubType," 8677 " A.SignalLevel, A.BatteryLevel, A.nValue, A.sValue," 8678 " A.LastUpdate, A.Favorite, A.SwitchType, A.HardwareID," 8679 " A.AddjValue, A.AddjMulti, A.AddjValue2, A.AddjMulti2," 8680 " A.LastLevel, A.CustomImage, A.StrParam1, A.StrParam2," 8681 " A.Protected, IFNULL(B.XOffset,0), IFNULL(B.YOffset,0), IFNULL(B.PlanID,0), A.Description," 8682 " A.Options, A.Color " 8683 "FROM DeviceStatus as A LEFT OUTER JOIN DeviceToPlansMap as B " 8684 "ON (B.DeviceRowID==a.ID) AND (B.DevSceneType==0) " 8685 "WHERE (A.HardwareID == %q) " 8686 "ORDER BY "); 8687 szQuery += szOrderBy; 8688 result = m_sql.safe_query(szQuery.c_str(), hardwareid.c_str(), order.c_str()); 8689 } 8690 else { 8691 szQuery = ( 8692 "SELECT A.ID, A.DeviceID, A.Unit, A.Name, A.Used,A.Type, A.SubType," 8693 " A.SignalLevel, A.BatteryLevel, A.nValue, A.sValue," 8694 " A.LastUpdate, A.Favorite, A.SwitchType, A.HardwareID," 8695 " A.AddjValue, A.AddjMulti, A.AddjValue2, A.AddjMulti2," 8696 " A.LastLevel, A.CustomImage, A.StrParam1, A.StrParam2," 8697 " A.Protected, IFNULL(B.XOffset,0), IFNULL(B.YOffset,0), IFNULL(B.PlanID,0), A.Description," 8698 " A.Options, A.Color " 8699 "FROM DeviceStatus as A LEFT OUTER JOIN DeviceToPlansMap as B " 8700 "ON (B.DeviceRowID==a.ID) AND (B.DevSceneType==0) " 8701 "ORDER BY "); 8702 szQuery += szOrderBy; 8703 result = m_sql.safe_query(szQuery.c_str(), order.c_str()); 8704 } 8705 } 8706 } 8707 else 8708 { 8709 if (iUser == -1) { 8710 return; 8711 } 8712 //Specific devices 8713 if (rowid != "") 8714 { 8715 //_log.Log(LOG_STATUS, "Getting device with id: %s for user %lu", rowid.c_str(), m_users[iUser].ID); 8716 result = m_sql.safe_query( 8717 "SELECT A.ID, A.DeviceID, A.Unit, A.Name, A.Used," 8718 " A.Type, A.SubType, A.SignalLevel, A.BatteryLevel," 8719 " A.nValue, A.sValue, A.LastUpdate, B.Favorite," 8720 " A.SwitchType, A.HardwareID, A.AddjValue," 8721 " A.AddjMulti, A.AddjValue2, A.AddjMulti2," 8722 " A.LastLevel, A.CustomImage, A.StrParam1," 8723 " A.StrParam2, A.Protected, 0 as XOffset," 8724 " 0 as YOffset, 0 as PlanID, A.Description," 8725 " A.Options, A.Color " 8726 "FROM DeviceStatus as A, SharedDevices as B " 8727 "WHERE (B.DeviceRowID==a.ID)" 8728 " AND (B.SharedUserID==%lu) AND (A.ID=='%q')", 8729 m_users[iUser].ID, rowid.c_str()); 8730 } 8731 else if ((planID != "") && (planID != "0")) 8732 result = m_sql.safe_query( 8733 "SELECT A.ID, A.DeviceID, A.Unit, A.Name, A.Used," 8734 " A.Type, A.SubType, A.SignalLevel, A.BatteryLevel," 8735 " A.nValue, A.sValue, A.LastUpdate, B.Favorite," 8736 " A.SwitchType, A.HardwareID, A.AddjValue," 8737 " A.AddjMulti, A.AddjValue2, A.AddjMulti2," 8738 " A.LastLevel, A.CustomImage, A.StrParam1," 8739 " A.StrParam2, A.Protected, C.XOffset," 8740 " C.YOffset, C.PlanID, A.Description," 8741 " A.Options, A.Color " 8742 "FROM DeviceStatus as A, SharedDevices as B," 8743 " DeviceToPlansMap as C " 8744 "WHERE (C.PlanID=='%q') AND (C.DeviceRowID==a.ID)" 8745 " AND (B.DeviceRowID==a.ID) " 8746 "AND (B.SharedUserID==%lu) ORDER BY C.[Order]", 8747 planID.c_str(), m_users[iUser].ID); 8748 else if ((floorID != "") && (floorID != "0")) 8749 result = m_sql.safe_query( 8750 "SELECT A.ID, A.DeviceID, A.Unit, A.Name, A.Used," 8751 " A.Type, A.SubType, A.SignalLevel, A.BatteryLevel," 8752 " A.nValue, A.sValue, A.LastUpdate, B.Favorite," 8753 " A.SwitchType, A.HardwareID, A.AddjValue," 8754 " A.AddjMulti, A.AddjValue2, A.AddjMulti2," 8755 " A.LastLevel, A.CustomImage, A.StrParam1," 8756 " A.StrParam2, A.Protected, C.XOffset, C.YOffset," 8757 " C.PlanID, A.Description," 8758 " A.Options, A.Color " 8759 "FROM DeviceStatus as A, SharedDevices as B," 8760 " DeviceToPlansMap as C, Plans as D " 8761 "WHERE (D.FloorplanID=='%q') AND (D.ID==C.PlanID)" 8762 " AND (C.DeviceRowID==a.ID) AND (B.DeviceRowID==a.ID)" 8763 " AND (B.SharedUserID==%lu) ORDER BY C.[Order]", 8764 floorID.c_str(), m_users[iUser].ID); 8765 else { 8766 if (!bDisplayHidden) 8767 { 8768 //Build a list of Hidden Devices 8769 result = m_sql.safe_query("SELECT ID FROM Plans WHERE (Name=='$Hidden Devices')"); 8770 if (!result.empty()) 8771 { 8772 std::string pID = result[0][0]; 8773 result = m_sql.safe_query("SELECT DeviceRowID FROM DeviceToPlansMap WHERE (PlanID=='%q') AND (DevSceneType==0)", 8774 pID.c_str()); 8775 if (!result.empty()) 8776 { 8777 std::vector<std::vector<std::string> >::const_iterator ittP; 8778 for (ittP = result.begin(); ittP != result.end(); ++ittP) 8779 { 8780 _HiddenDevices.insert(ittP[0][0]); 8781 } 8782 } 8783 } 8784 bAllowDeviceToBeHidden = true; 8785 } 8786 8787 if (order.empty() || (!isAlpha)) 8788 { 8789 strcpy(szOrderBy, "A.[Order],A.LastUpdate DESC"); 8790 } 8791 else 8792 { 8793 sprintf(szOrderBy, "A.[Order],A.%%s ASC"); 8794 } 8795 // _log.Log(LOG_STATUS, "Getting all devices for user %lu", m_users[iUser].ID); 8796 szQuery = ( 8797 "SELECT A.ID, A.DeviceID, A.Unit, A.Name, A.Used," 8798 " A.Type, A.SubType, A.SignalLevel, A.BatteryLevel," 8799 " A.nValue, A.sValue, A.LastUpdate, B.Favorite," 8800 " A.SwitchType, A.HardwareID, A.AddjValue," 8801 " A.AddjMulti, A.AddjValue2, A.AddjMulti2," 8802 " A.LastLevel, A.CustomImage, A.StrParam1," 8803 " A.StrParam2, A.Protected, IFNULL(C.XOffset,0)," 8804 " IFNULL(C.YOffset,0), IFNULL(C.PlanID,0), A.Description," 8805 " A.Options, A.Color " 8806 "FROM DeviceStatus as A, SharedDevices as B " 8807 "LEFT OUTER JOIN DeviceToPlansMap as C ON (C.DeviceRowID==A.ID)" 8808 "WHERE (B.DeviceRowID==A.ID)" 8809 " AND (B.SharedUserID==%lu) ORDER BY "); 8810 szQuery += szOrderBy; 8811 result = m_sql.safe_query(szQuery.c_str(), m_users[iUser].ID, order.c_str()); 8812 } 8813 } 8814 8815 if (!result.empty()) 8816 { 8817 for (const auto & itt : result) 8818 { 8819 std::vector<std::string> sd = itt; 8820 8821 unsigned char favorite = atoi(sd[12].c_str()); 8822 if ((planID != "") && (planID != "0")) 8823 favorite = 1; 8824 8825 //Check if we only want favorite devices 8826 if ((bFetchFavorites) && (!favorite)) 8827 continue; 8828 8829 std::string sDeviceName = sd[3]; 8830 8831 if (!bDisplayHidden) 8832 { 8833 if (_HiddenDevices.find(sd[0]) != _HiddenDevices.end()) 8834 continue; 8835 if (sDeviceName[0] == '$') 8836 { 8837 if (bAllowDeviceToBeHidden) 8838 continue; 8839 if (planID.size() > 0) 8840 sDeviceName = sDeviceName.substr(1); 8841 } 8842 } 8843 int hardwareID = atoi(sd[14].c_str()); 8844 std::map<int, _tHardwareListInt>::iterator hItt = _hardwareNames.find(hardwareID); 8845 if (hItt != _hardwareNames.end()) 8846 { 8847 //ignore sensors where the hardware is disabled 8848 if ((!bDisplayDisabled) && (!(*hItt).second.Enabled)) 8849 continue; 8850 } 8851 8852 unsigned int dType = atoi(sd[5].c_str()); 8853 unsigned int dSubType = atoi(sd[6].c_str()); 8854 unsigned int used = atoi(sd[4].c_str()); 8855 int nValue = atoi(sd[9].c_str()); 8856 std::string sValue = sd[10]; 8857 std::string sLastUpdate = sd[11]; 8858 if (sLastUpdate.size() > 19) 8859 sLastUpdate = sLastUpdate.substr(0, 19); 8860 8861 if (iLastUpdate != 0) 8862 { 8863 time_t cLastUpdate; 8864 ParseSQLdatetime(cLastUpdate, tLastUpdate, sLastUpdate, tm1.tm_isdst); 8865 if (cLastUpdate <= iLastUpdate) 8866 continue; 8867 } 8868 8869 _eSwitchType switchtype = (_eSwitchType)atoi(sd[13].c_str()); 8870 _eMeterType metertype = (_eMeterType)switchtype; 8871 double AddjValue = atof(sd[15].c_str()); 8872 double AddjMulti = atof(sd[16].c_str()); 8873 double AddjValue2 = atof(sd[17].c_str()); 8874 double AddjMulti2 = atof(sd[18].c_str()); 8875 int LastLevel = atoi(sd[19].c_str()); 8876 int CustomImage = atoi(sd[20].c_str()); 8877 std::string strParam1 = base64_encode(sd[21]); 8878 std::string strParam2 = base64_encode(sd[22]); 8879 int iProtected = atoi(sd[23].c_str()); 8880 8881 std::string Description = sd[27]; 8882 std::string sOptions = sd[28]; 8883 std::string sColor = sd[29]; 8884 std::map<std::string, std::string> options = m_sql.BuildDeviceOptions(sOptions); 8885 8886 struct tm ntime; 8887 time_t checktime; 8888 ParseSQLdatetime(checktime, ntime, sLastUpdate, tm1.tm_isdst); 8889 bool bHaveTimeout = (now - checktime >= SensorTimeOut * 60); 8890 8891 if (dType == pTypeTEMP_RAIN) 8892 continue; //dont want you for now 8893 8894 if ((rused == "true") && (!used)) 8895 continue; 8896 8897 if ( 8898 (rused == "false") && 8899 (used) 8900 ) 8901 continue; 8902 if (rfilter != "") 8903 { 8904 if (rfilter == "light") 8905 { 8906 if ( 8907 (dType != pTypeLighting1) && 8908 (dType != pTypeLighting2) && 8909 (dType != pTypeLighting3) && 8910 (dType != pTypeLighting4) && 8911 (dType != pTypeLighting5) && 8912 (dType != pTypeLighting6) && 8913 (dType != pTypeFan) && 8914 (dType != pTypeColorSwitch) && 8915 (dType != pTypeSecurity1) && 8916 (dType != pTypeSecurity2) && 8917 (dType != pTypeEvohome) && 8918 (dType != pTypeEvohomeRelay) && 8919 (dType != pTypeCurtain) && 8920 (dType != pTypeBlinds) && 8921 (dType != pTypeRFY) && 8922 (dType != pTypeChime) && 8923 (dType != pTypeThermostat2) && 8924 (dType != pTypeThermostat3) && 8925 (dType != pTypeThermostat4) && 8926 (dType != pTypeRemote) && 8927 (dType != pTypeGeneralSwitch) && 8928 (dType != pTypeHomeConfort) && 8929 (dType != pTypeChime) && 8930 (dType != pTypeFS20) && 8931 (!((dType == pTypeRego6XXValue) && (dSubType == sTypeRego6XXStatus))) && 8932 (!((dType == pTypeRadiator1) && (dSubType == sTypeSmartwaresSwitchRadiator)))&& 8933 (dType != pTypeHunter) 8934 ) 8935 continue; 8936 } 8937 else if (rfilter == "temp") 8938 { 8939 if ( 8940 (dType != pTypeTEMP) && 8941 (dType != pTypeHUM) && 8942 (dType != pTypeTEMP_HUM) && 8943 (dType != pTypeTEMP_HUM_BARO) && 8944 (dType != pTypeTEMP_BARO) && 8945 (dType != pTypeEvohomeZone) && 8946 (dType != pTypeEvohomeWater) && 8947 (!((dType == pTypeWIND) && (dSubType == sTypeWIND4))) && 8948 (!((dType == pTypeUV) && (dSubType == sTypeUV3))) && 8949 (!((dType == pTypeGeneral) && (dSubType == sTypeSystemTemp))) && 8950 (dType != pTypeThermostat1) && 8951 (!((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorTemp))) && 8952 (dType != pTypeRego6XXTemp) 8953 ) 8954 continue; 8955 } 8956 else if (rfilter == "weather") 8957 { 8958 if ( 8959 (dType != pTypeWIND) && 8960 (dType != pTypeRAIN) && 8961 (dType != pTypeTEMP_HUM_BARO) && 8962 (dType != pTypeTEMP_BARO) && 8963 (dType != pTypeUV) && 8964 (!((dType == pTypeGeneral) && (dSubType == sTypeVisibility))) && 8965 (!((dType == pTypeGeneral) && (dSubType == sTypeBaro))) && 8966 (!((dType == pTypeGeneral) && (dSubType == sTypeSolarRadiation))) 8967 ) 8968 continue; 8969 } 8970 else if (rfilter == "utility") 8971 { 8972 if ( 8973 (dType != pTypeRFXMeter) && 8974 (!((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorAD))) && 8975 (!((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorVolt))) && 8976 (!((dType == pTypeGeneral) && (dSubType == sTypeVoltage))) && 8977 (!((dType == pTypeGeneral) && (dSubType == sTypeCurrent))) && 8978 (!((dType == pTypeGeneral) && (dSubType == sTypeTextStatus))) && 8979 (!((dType == pTypeGeneral) && (dSubType == sTypeAlert))) && 8980 (!((dType == pTypeGeneral) && (dSubType == sTypePressure))) && 8981 (!((dType == pTypeGeneral) && (dSubType == sTypeSoilMoisture))) && 8982 (!((dType == pTypeGeneral) && (dSubType == sTypeLeafWetness))) && 8983 (!((dType == pTypeGeneral) && (dSubType == sTypePercentage))) && 8984 (!((dType == pTypeGeneral) && (dSubType == sTypeWaterflow))) && 8985 (!((dType == pTypeGeneral) && (dSubType == sTypeCustom))) && 8986 (!((dType == pTypeGeneral) && (dSubType == sTypeFan))) && 8987 (!((dType == pTypeGeneral) && (dSubType == sTypeSoundLevel))) && 8988 (!((dType == pTypeGeneral) && (dSubType == sTypeZWaveClock))) && 8989 (!((dType == pTypeGeneral) && (dSubType == sTypeZWaveThermostatMode))) && 8990 (!((dType == pTypeGeneral) && (dSubType == sTypeZWaveThermostatFanMode))) && 8991 (!((dType == pTypeGeneral) && (dSubType == sTypeZWaveThermostatOperatingState))) && 8992 (!((dType == pTypeGeneral) && (dSubType == sTypeDistance))) && 8993 (!((dType == pTypeGeneral) && (dSubType == sTypeCounterIncremental))) && 8994 (!((dType == pTypeGeneral) && (dSubType == sTypeManagedCounter))) && 8995 (!((dType == pTypeGeneral) && (dSubType == sTypeKwh))) && 8996 (dType != pTypeCURRENT) && 8997 (dType != pTypeCURRENTENERGY) && 8998 (dType != pTypeENERGY) && 8999 (dType != pTypePOWER) && 9000 (dType != pTypeP1Power) && 9001 (dType != pTypeP1Gas) && 9002 (dType != pTypeYouLess) && 9003 (dType != pTypeAirQuality) && 9004 (dType != pTypeLux) && 9005 (dType != pTypeUsage) && 9006 (!((dType == pTypeRego6XXValue) && (dSubType == sTypeRego6XXCounter))) && 9007 (!((dType == pTypeThermostat) && (dSubType == sTypeThermSetpoint))) && 9008 (dType != pTypeWEIGHT) && 9009 (!((dType == pTypeRadiator1) && (dSubType == sTypeSmartwares))) 9010 ) 9011 continue; 9012 } 9013 else if (rfilter == "wind") 9014 { 9015 if ( 9016 (dType != pTypeWIND) 9017 ) 9018 continue; 9019 } 9020 else if (rfilter == "rain") 9021 { 9022 if ( 9023 (dType != pTypeRAIN) 9024 ) 9025 continue; 9026 } 9027 else if (rfilter == "uv") 9028 { 9029 if ( 9030 (dType != pTypeUV) 9031 ) 9032 continue; 9033 } 9034 else if (rfilter == "baro") 9035 { 9036 if ( 9037 (dType != pTypeTEMP_HUM_BARO) && 9038 (dType != pTypeTEMP_BARO) 9039 ) 9040 continue; 9041 } 9042 else if (rfilter == "zwavealarms") 9043 { 9044 if (!((dType == pTypeGeneral) && (dSubType == sTypeZWaveAlarm))) 9045 continue; 9046 } 9047 } 9048 9049 // has this device already been seen, now with different plan? 9050 // assume results are ordered such that same device is adjacent 9051 // if the idx and the Type are equal (type to prevent matching against Scene with same idx) 9052 std::string thisIdx = sd[0]; 9053 int devIdx = atoi(thisIdx.c_str()); 9054 9055 if ((ii > 0) && thisIdx == root["result"][ii - 1]["idx"].asString()) { 9056 std::string typeOfThisOne = RFX_Type_Desc(dType, 1); 9057 if (typeOfThisOne == root["result"][ii - 1]["Type"].asString()) { 9058 root["result"][ii - 1]["PlanIDs"].append(atoi(sd[26].c_str())); 9059 continue; 9060 } 9061 } 9062 9063 root["result"][ii]["HardwareID"] = hardwareID; 9064 if (_hardwareNames.find(hardwareID) == _hardwareNames.end()) 9065 { 9066 root["result"][ii]["HardwareName"] = "Unknown?"; 9067 root["result"][ii]["HardwareTypeVal"] = 0; 9068 root["result"][ii]["HardwareType"] = "Unknown?"; 9069 } 9070 else 9071 { 9072 root["result"][ii]["HardwareName"] = _hardwareNames[hardwareID].Name; 9073 root["result"][ii]["HardwareTypeVal"] = _hardwareNames[hardwareID].HardwareTypeVal; 9074 root["result"][ii]["HardwareType"] = _hardwareNames[hardwareID].HardwareType; 9075 } 9076 root["result"][ii]["idx"] = sd[0]; 9077 root["result"][ii]["Protected"] = (iProtected != 0); 9078 9079 CDomoticzHardwareBase *pHardware = m_mainworker.GetHardware(hardwareID); 9080 if (pHardware != NULL) 9081 { 9082 if (pHardware->HwdType == HTYPE_SolarEdgeAPI) 9083 { 9084 int seSensorTimeOut = 60 * 24 * 60; 9085 bHaveTimeout = (now - checktime >= seSensorTimeOut * 60); 9086 } 9087 else if (pHardware->HwdType == HTYPE_Wunderground) 9088 { 9089 CWunderground *pWHardware = reinterpret_cast<CWunderground *>(pHardware); 9090 std::string forecast_url = pWHardware->GetForecastURL(); 9091 if (forecast_url != "") 9092 { 9093 root["result"][ii]["forecast_url"] = base64_encode(forecast_url); 9094 } 9095 } 9096 else if (pHardware->HwdType == HTYPE_DarkSky) 9097 { 9098 CDarkSky *pWHardware = reinterpret_cast<CDarkSky*>(pHardware); 9099 std::string forecast_url = pWHardware->GetForecastURL(); 9100 if (forecast_url != "") 9101 { 9102 root["result"][ii]["forecast_url"] = base64_encode(forecast_url); 9103 } 9104 } 9105 else if (pHardware->HwdType == HTYPE_AccuWeather) 9106 { 9107 CAccuWeather *pWHardware = reinterpret_cast<CAccuWeather*>(pHardware); 9108 std::string forecast_url = pWHardware->GetForecastURL(); 9109 if (forecast_url != "") 9110 { 9111 root["result"][ii]["forecast_url"] = base64_encode(forecast_url); 9112 } 9113 } 9114 else if (pHardware->HwdType == HTYPE_OpenWeatherMap) 9115 { 9116 COpenWeatherMap *pWHardware = reinterpret_cast<COpenWeatherMap*>(pHardware); 9117 std::string forecast_url = pWHardware->GetForecastURL(); 9118 if (forecast_url != "") 9119 { 9120 root["result"][ii]["forecast_url"] = base64_encode(forecast_url); 9121 } 9122 } 9123 else if (pHardware->HwdType == HTYPE_BuienRadar) 9124 { 9125 CBuienRadar* pWHardware = reinterpret_cast<CBuienRadar*>(pHardware); 9126 std::string forecast_url = pWHardware->GetForecastURL(); 9127 if (forecast_url != "") 9128 { 9129 root["result"][ii]["forecast_url"] = base64_encode(forecast_url); 9130 } 9131 } 9132 } 9133 9134 if ((pHardware != NULL) && (pHardware->HwdType == HTYPE_PythonPlugin)) 9135 { 9136 // Device ID special formatting should not be applied to Python plugins 9137 root["result"][ii]["ID"] = sd[1]; 9138 } 9139 else 9140 { 9141 sprintf(szData, "%04X", (unsigned int)atoi(sd[1].c_str())); 9142 if ( 9143 (dType == pTypeTEMP) || 9144 (dType == pTypeTEMP_BARO) || 9145 (dType == pTypeTEMP_HUM) || 9146 (dType == pTypeTEMP_HUM_BARO) || 9147 (dType == pTypeBARO) || 9148 (dType == pTypeHUM) || 9149 (dType == pTypeWIND) || 9150 (dType == pTypeRAIN) || 9151 (dType == pTypeUV) || 9152 (dType == pTypeCURRENT) || 9153 (dType == pTypeCURRENTENERGY) || 9154 (dType == pTypeENERGY) || 9155 (dType == pTypeRFXMeter) || 9156 (dType == pTypeAirQuality) || 9157 (dType == pTypeRFXSensor) || 9158 (dType == pTypeP1Power) || 9159 (dType == pTypeP1Gas) 9160 ) 9161 { 9162 root["result"][ii]["ID"] = szData; 9163 } 9164 else 9165 { 9166 root["result"][ii]["ID"] = sd[1]; 9167 } 9168 } 9169 root["result"][ii]["Unit"] = atoi(sd[2].c_str()); 9170 root["result"][ii]["Type"] = RFX_Type_Desc(dType, 1); 9171 root["result"][ii]["SubType"] = RFX_Type_SubType_Desc(dType, dSubType); 9172 root["result"][ii]["TypeImg"] = RFX_Type_Desc(dType, 2); 9173 root["result"][ii]["Name"] = sDeviceName; 9174 root["result"][ii]["Description"] = Description; 9175 root["result"][ii]["Used"] = used; 9176 root["result"][ii]["Favorite"] = favorite; 9177 9178 int iSignalLevel = atoi(sd[7].c_str()); 9179 if (iSignalLevel < 12) 9180 root["result"][ii]["SignalLevel"] = iSignalLevel; 9181 else 9182 root["result"][ii]["SignalLevel"] = "-"; 9183 root["result"][ii]["BatteryLevel"] = atoi(sd[8].c_str()); 9184 root["result"][ii]["LastUpdate"] = sLastUpdate; 9185 root["result"][ii]["CustomImage"] = CustomImage; 9186 root["result"][ii]["XOffset"] = sd[24].c_str(); 9187 root["result"][ii]["YOffset"] = sd[25].c_str(); 9188 root["result"][ii]["PlanID"] = sd[26].c_str(); 9189 Json::Value jsonArray; 9190 jsonArray.append(atoi(sd[26].c_str())); 9191 root["result"][ii]["PlanIDs"] = jsonArray; 9192 root["result"][ii]["AddjValue"] = AddjValue; 9193 root["result"][ii]["AddjMulti"] = AddjMulti; 9194 root["result"][ii]["AddjValue2"] = AddjValue2; 9195 root["result"][ii]["AddjMulti2"] = AddjMulti2; 9196 9197 std::stringstream s_data; 9198 s_data << int(nValue) << ", " << sValue; 9199 root["result"][ii]["Data"] = s_data.str(); 9200 9201 root["result"][ii]["Notifications"] = (m_notifications.HasNotifications(sd[0]) == true) ? "true" : "false"; 9202 root["result"][ii]["ShowNotifications"] = true; 9203 9204 bool bHasTimers = false; 9205 9206 if ( 9207 (dType == pTypeLighting1) || 9208 (dType == pTypeLighting2) || 9209 (dType == pTypeLighting3) || 9210 (dType == pTypeLighting4) || 9211 (dType == pTypeLighting5) || 9212 (dType == pTypeLighting6) || 9213 (dType == pTypeFan) || 9214 (dType == pTypeColorSwitch) || 9215 (dType == pTypeCurtain) || 9216 (dType == pTypeBlinds) || 9217 (dType == pTypeRFY) || 9218 (dType == pTypeChime) || 9219 (dType == pTypeThermostat2) || 9220 (dType == pTypeThermostat3) || 9221 (dType == pTypeThermostat4) || 9222 (dType == pTypeRemote) || 9223 (dType == pTypeGeneralSwitch) || 9224 (dType == pTypeHomeConfort) || 9225 (dType == pTypeFS20) || 9226 ((dType == pTypeRadiator1) && (dSubType == sTypeSmartwaresSwitchRadiator)) || 9227 ((dType == pTypeRego6XXValue) && (dSubType == sTypeRego6XXStatus)) || 9228 (dType == pTypeHunter) 9229 ) 9230 { 9231 //add light details 9232 bHasTimers = m_sql.HasTimers(sd[0]); 9233 9234 bHaveTimeout = false; 9235 #ifdef WITH_OPENZWAVE 9236 if (pHardware != NULL) 9237 { 9238 if (pHardware->HwdType == HTYPE_OpenZWave) 9239 { 9240 COpenZWave *pZWave = reinterpret_cast<COpenZWave*>(pHardware); 9241 unsigned long ID; 9242 std::stringstream s_strid; 9243 s_strid << std::hex << sd[1]; 9244 s_strid >> ID; 9245 int nodeID = (ID & 0x0000FF00) >> 8; 9246 bHaveTimeout = pZWave->HasNodeFailed(nodeID); 9247 } 9248 } 9249 #endif 9250 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9251 9252 std::string lstatus = ""; 9253 int llevel = 0; 9254 bool bHaveDimmer = false; 9255 bool bHaveGroupCmd = false; 9256 int maxDimLevel = 0; 9257 9258 GetLightStatus(dType, dSubType, switchtype, nValue, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd); 9259 9260 root["result"][ii]["Status"] = lstatus; 9261 root["result"][ii]["StrParam1"] = strParam1; 9262 root["result"][ii]["StrParam2"] = strParam2; 9263 9264 std::string IconFile = "Light"; 9265 std::map<int, int>::const_iterator ittIcon = m_custom_light_icons_lookup.find(CustomImage); 9266 if (ittIcon != m_custom_light_icons_lookup.end()) 9267 { 9268 IconFile = m_custom_light_icons[ittIcon->second].RootFile; 9269 } 9270 root["result"][ii]["Image"] = IconFile; 9271 9272 if (switchtype == STYPE_Dimmer) 9273 { 9274 root["result"][ii]["Level"] = LastLevel; 9275 int iLevel = round((float(maxDimLevel) / 100.0f)*LastLevel); 9276 root["result"][ii]["LevelInt"] = iLevel; 9277 if ((dType == pTypeColorSwitch) || 9278 (dType == pTypeLighting5 && dSubType == sTypeTRC02) || 9279 (dType == pTypeLighting5 && dSubType == sTypeTRC02_2) || 9280 (dType == pTypeGeneralSwitch && dSubType == sSwitchTypeTRC02) || 9281 (dType == pTypeGeneralSwitch && dSubType == sSwitchTypeTRC02_2)) 9282 { 9283 _tColor color(sColor); 9284 std::string jsonColor = color.toJSONString(); 9285 root["result"][ii]["Color"] = jsonColor; 9286 llevel = LastLevel; 9287 if (lstatus == "Set Level" || lstatus == "Set Color") 9288 { 9289 sprintf(szTmp, "Set Level: %d %%", LastLevel); 9290 root["result"][ii]["Status"] = szTmp; 9291 } 9292 } 9293 } 9294 else 9295 { 9296 root["result"][ii]["Level"] = llevel; 9297 root["result"][ii]["LevelInt"] = atoi(sValue.c_str()); 9298 } 9299 root["result"][ii]["HaveDimmer"] = bHaveDimmer; 9300 std::string DimmerType = "none"; 9301 if (switchtype == STYPE_Dimmer) 9302 { 9303 DimmerType = "abs"; 9304 if (_hardwareNames.find(hardwareID) != _hardwareNames.end()) 9305 { 9306 // Milight V4/V5 bridges do not support absolute dimming for RGB or CW_WW lights 9307 if (_hardwareNames[hardwareID].HardwareTypeVal == HTYPE_LimitlessLights && 9308 atoi(_hardwareNames[hardwareID].Mode2.c_str()) != CLimitLess::LBTYPE_V6 && 9309 (atoi(_hardwareNames[hardwareID].Mode1.c_str()) == sTypeColor_RGB || 9310 atoi(_hardwareNames[hardwareID].Mode1.c_str()) == sTypeColor_White || 9311 atoi(_hardwareNames[hardwareID].Mode1.c_str()) == sTypeColor_CW_WW)) 9312 { 9313 DimmerType = "rel"; 9314 } 9315 } 9316 } 9317 root["result"][ii]["DimmerType"] = DimmerType; 9318 root["result"][ii]["MaxDimLevel"] = maxDimLevel; 9319 root["result"][ii]["HaveGroupCmd"] = bHaveGroupCmd; 9320 root["result"][ii]["SwitchType"] = Switch_Type_Desc(switchtype); 9321 root["result"][ii]["SwitchTypeVal"] = switchtype; 9322 uint64_t camIDX = m_mainworker.m_cameras.IsDevSceneInCamera(0, sd[0]); 9323 root["result"][ii]["UsedByCamera"] = (camIDX != 0) ? true : false; 9324 if (camIDX != 0) { 9325 std::stringstream scidx; 9326 scidx << camIDX; 9327 root["result"][ii]["CameraIdx"] = scidx.str(); 9328 } 9329 9330 bool bIsSubDevice = false; 9331 std::vector<std::vector<std::string> > resultSD; 9332 resultSD = m_sql.safe_query("SELECT ID FROM LightSubDevices WHERE (DeviceRowID=='%q')", 9333 sd[0].c_str()); 9334 bIsSubDevice = (resultSD.size() > 0); 9335 9336 root["result"][ii]["IsSubDevice"] = bIsSubDevice; 9337 9338 if (switchtype == STYPE_Doorbell) 9339 { 9340 root["result"][ii]["TypeImg"] = "doorbell"; 9341 root["result"][ii]["Status"] = "";//"Pressed"; 9342 } 9343 else if (switchtype == STYPE_DoorContact) 9344 { 9345 if (CustomImage == 0) 9346 { 9347 root["result"][ii]["Image"] = "Door"; 9348 } 9349 root["result"][ii]["TypeImg"] = "door"; 9350 bool bIsOn = IsLightSwitchOn(lstatus); 9351 root["result"][ii]["InternalState"] = (bIsOn == true) ? "Open" : "Closed"; 9352 if (bIsOn) { 9353 lstatus = "Open"; 9354 } 9355 else { 9356 lstatus = "Closed"; 9357 } 9358 root["result"][ii]["Status"] = lstatus; 9359 } 9360 else if (switchtype == STYPE_DoorLock) 9361 { 9362 if (CustomImage == 0) 9363 { 9364 root["result"][ii]["Image"] = "Door"; 9365 } 9366 root["result"][ii]["TypeImg"] = "door"; 9367 bool bIsOn = IsLightSwitchOn(lstatus); 9368 root["result"][ii]["InternalState"] = (bIsOn == true) ? "Locked" : "Unlocked"; 9369 if (bIsOn) { 9370 lstatus = "Locked"; 9371 } 9372 else { 9373 lstatus = "Unlocked"; 9374 } 9375 root["result"][ii]["Status"] = lstatus; 9376 } 9377 else if (switchtype == STYPE_DoorLockInverted) 9378 { 9379 if (CustomImage == 0) 9380 { 9381 root["result"][ii]["Image"] = "Door"; 9382 } 9383 root["result"][ii]["TypeImg"] = "door"; 9384 bool bIsOn = IsLightSwitchOn(lstatus); 9385 root["result"][ii]["InternalState"] = (bIsOn == true) ? "Unlocked" : "Locked"; 9386 if (bIsOn) { 9387 lstatus = "Unlocked"; 9388 } 9389 else { 9390 lstatus = "Locked"; 9391 } 9392 root["result"][ii]["Status"] = lstatus; 9393 } 9394 else if (switchtype == STYPE_PushOn) 9395 { 9396 if (CustomImage == 0) 9397 { 9398 root["result"][ii]["Image"] = "Push"; 9399 } 9400 root["result"][ii]["TypeImg"] = "push"; 9401 root["result"][ii]["Status"] = ""; 9402 root["result"][ii]["InternalState"] = (IsLightSwitchOn(lstatus) == true) ? "On" : "Off"; 9403 } 9404 else if (switchtype == STYPE_PushOff) 9405 { 9406 if (CustomImage == 0) 9407 { 9408 root["result"][ii]["Image"] = "Push"; 9409 } 9410 root["result"][ii]["TypeImg"] = "push"; 9411 root["result"][ii]["Status"] = ""; 9412 root["result"][ii]["TypeImg"] = "pushoff"; 9413 } 9414 else if (switchtype == STYPE_X10Siren) 9415 root["result"][ii]["TypeImg"] = "siren"; 9416 else if (switchtype == STYPE_SMOKEDETECTOR) 9417 { 9418 root["result"][ii]["TypeImg"] = "smoke"; 9419 root["result"][ii]["SwitchTypeVal"] = STYPE_SMOKEDETECTOR; 9420 root["result"][ii]["SwitchType"] = Switch_Type_Desc(STYPE_SMOKEDETECTOR); 9421 } 9422 else if (switchtype == STYPE_Contact) 9423 { 9424 if (CustomImage == 0) 9425 { 9426 root["result"][ii]["Image"] = "Contact"; 9427 } 9428 root["result"][ii]["TypeImg"] = "contact"; 9429 bool bIsOn = IsLightSwitchOn(lstatus); 9430 if (bIsOn) { 9431 lstatus = "Open"; 9432 } 9433 else { 9434 lstatus = "Closed"; 9435 } 9436 root["result"][ii]["Status"] = lstatus; 9437 } 9438 else if (switchtype == STYPE_Media) 9439 { 9440 if ((pHardware != NULL) && (pHardware->HwdType == HTYPE_LogitechMediaServer)) 9441 root["result"][ii]["TypeImg"] = "LogitechMediaServer"; 9442 else 9443 root["result"][ii]["TypeImg"] = "Media"; 9444 root["result"][ii]["Status"] = Media_Player_States((_eMediaStatus)nValue); 9445 lstatus = sValue; 9446 } 9447 else if ( 9448 (switchtype == STYPE_Blinds) || 9449 (switchtype == STYPE_VenetianBlindsUS) || 9450 (switchtype == STYPE_VenetianBlindsEU) 9451 ) 9452 { 9453 root["result"][ii]["TypeImg"] = "blinds"; 9454 if ((lstatus == "On") || (lstatus == "Close inline relay")) { 9455 lstatus = "Closed"; 9456 } 9457 else if ((lstatus == "Stop") || (lstatus == "Stop inline relay")) { 9458 lstatus = "Stopped"; 9459 } 9460 else { 9461 lstatus = "Open"; 9462 } 9463 root["result"][ii]["Status"] = lstatus; 9464 } 9465 else if (switchtype == STYPE_BlindsInverted) 9466 { 9467 root["result"][ii]["TypeImg"] = "blinds"; 9468 if (lstatus == "On") { 9469 lstatus = "Open"; 9470 } 9471 else { 9472 lstatus = "Closed"; 9473 } 9474 root["result"][ii]["Status"] = lstatus; 9475 } 9476 else if ((switchtype == STYPE_BlindsPercentage) || (switchtype == STYPE_BlindsPercentageInverted)) 9477 { 9478 root["result"][ii]["TypeImg"] = "blinds"; 9479 root["result"][ii]["Level"] = LastLevel; 9480 int iLevel = round((float(maxDimLevel) / 100.0f)*LastLevel); 9481 root["result"][ii]["LevelInt"] = iLevel; 9482 if (lstatus == "On") { 9483 lstatus = (switchtype == STYPE_BlindsPercentage) ? "Closed" : "Open"; 9484 } 9485 else if (lstatus == "Off") { 9486 lstatus = (switchtype == STYPE_BlindsPercentage) ? "Open" : "Closed"; 9487 } 9488 9489 root["result"][ii]["Status"] = lstatus; 9490 } 9491 else if (switchtype == STYPE_Dimmer) 9492 { 9493 root["result"][ii]["TypeImg"] = "dimmer"; 9494 } 9495 else if (switchtype == STYPE_Motion) 9496 { 9497 root["result"][ii]["TypeImg"] = "motion"; 9498 } 9499 else if (switchtype == STYPE_Selector) 9500 { 9501 std::string selectorStyle = options["SelectorStyle"]; 9502 std::string levelOffHidden = options["LevelOffHidden"]; 9503 std::string levelNames = options["LevelNames"]; 9504 std::string levelActions = options["LevelActions"]; 9505 if (selectorStyle.empty()) { 9506 selectorStyle.assign("0"); // default is 'button set' 9507 } 9508 if (levelOffHidden.empty()) { 9509 levelOffHidden.assign("false"); // default is 'not hidden' 9510 } 9511 if (levelNames.empty()) { 9512 levelNames.assign("Off"); // default is Off only 9513 } 9514 root["result"][ii]["TypeImg"] = "Light"; 9515 root["result"][ii]["SelectorStyle"] = atoi(selectorStyle.c_str()); 9516 root["result"][ii]["LevelOffHidden"] = (levelOffHidden == "true"); 9517 root["result"][ii]["LevelNames"] = base64_encode(levelNames); 9518 root["result"][ii]["LevelActions"] = base64_encode(levelActions); 9519 } 9520 sprintf(szData, "%s", lstatus.c_str()); 9521 root["result"][ii]["Data"] = szData; 9522 } 9523 else if (dType == pTypeSecurity1) 9524 { 9525 std::string lstatus = ""; 9526 int llevel = 0; 9527 bool bHaveDimmer = false; 9528 bool bHaveGroupCmd = false; 9529 int maxDimLevel = 0; 9530 9531 GetLightStatus(dType, dSubType, switchtype, nValue, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd); 9532 9533 root["result"][ii]["Status"] = lstatus; 9534 root["result"][ii]["HaveDimmer"] = bHaveDimmer; 9535 root["result"][ii]["MaxDimLevel"] = maxDimLevel; 9536 root["result"][ii]["HaveGroupCmd"] = bHaveGroupCmd; 9537 root["result"][ii]["SwitchType"] = "Security"; 9538 root["result"][ii]["SwitchTypeVal"] = switchtype; //was 0?; 9539 root["result"][ii]["TypeImg"] = "security"; 9540 root["result"][ii]["StrParam1"] = strParam1; 9541 root["result"][ii]["StrParam2"] = strParam2; 9542 root["result"][ii]["Protected"] = (iProtected != 0); 9543 9544 if ( 9545 (dSubType == sTypeKD101) 9546 || (dSubType == sTypeSA30) 9547 || (dSubType == sTypeRM174RF) 9548 || (switchtype == STYPE_SMOKEDETECTOR) 9549 ) 9550 { 9551 root["result"][ii]["SwitchTypeVal"] = STYPE_SMOKEDETECTOR; 9552 root["result"][ii]["TypeImg"] = "smoke"; 9553 root["result"][ii]["SwitchType"] = Switch_Type_Desc(STYPE_SMOKEDETECTOR); 9554 } 9555 sprintf(szData, "%s", lstatus.c_str()); 9556 root["result"][ii]["Data"] = szData; 9557 root["result"][ii]["HaveTimeout"] = false; 9558 } 9559 else if (dType == pTypeSecurity2) 9560 { 9561 std::string lstatus = ""; 9562 int llevel = 0; 9563 bool bHaveDimmer = false; 9564 bool bHaveGroupCmd = false; 9565 int maxDimLevel = 0; 9566 9567 GetLightStatus(dType, dSubType, switchtype, nValue, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd); 9568 9569 root["result"][ii]["Status"] = lstatus; 9570 root["result"][ii]["HaveDimmer"] = bHaveDimmer; 9571 root["result"][ii]["MaxDimLevel"] = maxDimLevel; 9572 root["result"][ii]["HaveGroupCmd"] = bHaveGroupCmd; 9573 root["result"][ii]["SwitchType"] = "Security"; 9574 root["result"][ii]["SwitchTypeVal"] = switchtype; //was 0?; 9575 root["result"][ii]["TypeImg"] = "security"; 9576 root["result"][ii]["StrParam1"] = strParam1; 9577 root["result"][ii]["StrParam2"] = strParam2; 9578 root["result"][ii]["Protected"] = (iProtected != 0); 9579 sprintf(szData, "%s", lstatus.c_str()); 9580 root["result"][ii]["Data"] = szData; 9581 root["result"][ii]["HaveTimeout"] = false; 9582 } 9583 else if (dType == pTypeEvohome || dType == pTypeEvohomeRelay) 9584 { 9585 std::string lstatus = ""; 9586 int llevel = 0; 9587 bool bHaveDimmer = false; 9588 bool bHaveGroupCmd = false; 9589 int maxDimLevel = 0; 9590 9591 GetLightStatus(dType, dSubType, switchtype, nValue, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd); 9592 9593 root["result"][ii]["Status"] = lstatus; 9594 root["result"][ii]["HaveDimmer"] = bHaveDimmer; 9595 root["result"][ii]["MaxDimLevel"] = maxDimLevel; 9596 root["result"][ii]["HaveGroupCmd"] = bHaveGroupCmd; 9597 root["result"][ii]["SwitchType"] = "evohome"; 9598 root["result"][ii]["SwitchTypeVal"] = switchtype; //was 0?; 9599 root["result"][ii]["TypeImg"] = "override_mini"; 9600 root["result"][ii]["StrParam1"] = strParam1; 9601 root["result"][ii]["StrParam2"] = strParam2; 9602 root["result"][ii]["Protected"] = (iProtected != 0); 9603 9604 sprintf(szData, "%s", lstatus.c_str()); 9605 root["result"][ii]["Data"] = szData; 9606 root["result"][ii]["HaveTimeout"] = false; 9607 9608 if (dType == pTypeEvohomeRelay) 9609 { 9610 root["result"][ii]["SwitchType"] = "TPI"; 9611 root["result"][ii]["Level"] = llevel; 9612 root["result"][ii]["LevelInt"] = atoi(sValue.c_str()); 9613 if (root["result"][ii]["Unit"].asInt() > 100) 9614 root["result"][ii]["Protected"] = true; 9615 9616 sprintf(szData, "%s: %d", lstatus.c_str(), atoi(sValue.c_str())); 9617 root["result"][ii]["Data"] = szData; 9618 } 9619 } 9620 else if ((dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater)) 9621 { 9622 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9623 root["result"][ii]["TypeImg"] = "override_mini"; 9624 9625 std::vector<std::string> strarray; 9626 StringSplit(sValue, ";", strarray); 9627 if (strarray.size() >= 3) 9628 { 9629 int i = 0; 9630 double tempCelcius = atof(strarray[i++].c_str()); 9631 double temp = ConvertTemperature(tempCelcius, tempsign); 9632 double tempSetPoint; 9633 root["result"][ii]["Temp"] = temp; 9634 if (dType == pTypeEvohomeZone) 9635 { 9636 tempCelcius = atof(strarray[i++].c_str()); 9637 tempSetPoint = ConvertTemperature(tempCelcius, tempsign); 9638 root["result"][ii]["SetPoint"] = tempSetPoint; 9639 } 9640 else 9641 root["result"][ii]["State"] = strarray[i++]; 9642 9643 std::string strstatus = strarray[i++]; 9644 root["result"][ii]["Status"] = strstatus; 9645 9646 if ((dType == pTypeEvohomeZone || dType == pTypeEvohomeWater) && strarray.size() >= 4) 9647 { 9648 root["result"][ii]["Until"] = strarray[i++]; 9649 } 9650 if (dType == pTypeEvohomeZone) 9651 { 9652 if (tempCelcius == 325.1) 9653 sprintf(szTmp, "Off"); 9654 else 9655 sprintf(szTmp, "%.1f %c", tempSetPoint, tempsign); 9656 if (strarray.size() >= 4) 9657 sprintf(szData, "%.1f %c, (%s), %s until %s", temp, tempsign, szTmp, strstatus.c_str(), strarray[3].c_str()); 9658 else 9659 sprintf(szData, "%.1f %c, (%s), %s", temp, tempsign, szTmp, strstatus.c_str()); 9660 } 9661 else 9662 if (strarray.size() >= 4) 9663 sprintf(szData, "%.1f %c, %s, %s until %s", temp, tempsign, strarray[1].c_str(), strstatus.c_str(), strarray[3].c_str()); 9664 else 9665 sprintf(szData, "%.1f %c, %s, %s", temp, tempsign, strarray[1].c_str(), strstatus.c_str()); 9666 root["result"][ii]["Data"] = szData; 9667 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9668 } 9669 } 9670 else if ((dType == pTypeTEMP) || (dType == pTypeRego6XXTemp)) 9671 { 9672 double tvalue = ConvertTemperature(atof(sValue.c_str()), tempsign); 9673 root["result"][ii]["Temp"] = tvalue; 9674 sprintf(szData, "%.1f %c", tvalue, tempsign); 9675 root["result"][ii]["Data"] = szData; 9676 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9677 9678 _tTrendCalculator::_eTendencyType tstate = _tTrendCalculator::_eTendencyType::TENDENCY_UNKNOWN; 9679 uint64_t tID = ((uint64_t)(hardwareID & 0x7FFFFFFF) << 32) | (devIdx & 0x7FFFFFFF); 9680 if (m_mainworker.m_trend_calculator.find(tID) != m_mainworker.m_trend_calculator.end()) 9681 { 9682 tstate = m_mainworker.m_trend_calculator[tID].m_state; 9683 } 9684 root["result"][ii]["trend"] = (int)tstate; 9685 } 9686 else if (dType == pTypeThermostat1) 9687 { 9688 std::vector<std::string> strarray; 9689 StringSplit(sValue, ";", strarray); 9690 if (strarray.size() == 4) 9691 { 9692 double tvalue = ConvertTemperature(atof(strarray[0].c_str()), tempsign); 9693 root["result"][ii]["Temp"] = tvalue; 9694 sprintf(szData, "%.1f %c", tvalue, tempsign); 9695 root["result"][ii]["Data"] = szData; 9696 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9697 } 9698 } 9699 else if ((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorTemp)) 9700 { 9701 double tvalue = ConvertTemperature(atof(sValue.c_str()), tempsign); 9702 root["result"][ii]["Temp"] = tvalue; 9703 sprintf(szData, "%.1f %c", tvalue, tempsign); 9704 root["result"][ii]["Data"] = szData; 9705 root["result"][ii]["TypeImg"] = "temperature"; 9706 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9707 _tTrendCalculator::_eTendencyType tstate = _tTrendCalculator::_eTendencyType::TENDENCY_UNKNOWN; 9708 uint64_t tID = ((uint64_t)(hardwareID & 0x7FFFFFFF) << 32) | (devIdx & 0x7FFFFFFF); 9709 if (m_mainworker.m_trend_calculator.find(tID) != m_mainworker.m_trend_calculator.end()) 9710 { 9711 tstate = m_mainworker.m_trend_calculator[tID].m_state; 9712 } 9713 root["result"][ii]["trend"] = (int)tstate; 9714 } 9715 else if (dType == pTypeHUM) 9716 { 9717 root["result"][ii]["Humidity"] = nValue; 9718 root["result"][ii]["HumidityStatus"] = RFX_Humidity_Status_Desc(atoi(sValue.c_str())); 9719 sprintf(szData, "Humidity %d %%", nValue); 9720 root["result"][ii]["Data"] = szData; 9721 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9722 } 9723 else if (dType == pTypeTEMP_HUM) 9724 { 9725 std::vector<std::string> strarray; 9726 StringSplit(sValue, ";", strarray); 9727 if (strarray.size() == 3) 9728 { 9729 double tempCelcius = atof(strarray[0].c_str()); 9730 double temp = ConvertTemperature(tempCelcius, tempsign); 9731 int humidity = atoi(strarray[1].c_str()); 9732 9733 root["result"][ii]["Temp"] = temp; 9734 root["result"][ii]["Humidity"] = humidity; 9735 root["result"][ii]["HumidityStatus"] = RFX_Humidity_Status_Desc(atoi(strarray[2].c_str())); 9736 sprintf(szData, "%.1f %c, %d %%", temp, tempsign, atoi(strarray[1].c_str())); 9737 root["result"][ii]["Data"] = szData; 9738 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9739 9740 //Calculate dew point 9741 9742 sprintf(szTmp, "%.2f", ConvertTemperature(CalculateDewPoint(tempCelcius, humidity), tempsign)); 9743 root["result"][ii]["DewPoint"] = szTmp; 9744 9745 _tTrendCalculator::_eTendencyType tstate = _tTrendCalculator::_eTendencyType::TENDENCY_UNKNOWN; 9746 uint64_t tID = ((uint64_t)(hardwareID & 0x7FFFFFFF) << 32) | (devIdx & 0x7FFFFFFF); 9747 if (m_mainworker.m_trend_calculator.find(tID) != m_mainworker.m_trend_calculator.end()) 9748 { 9749 tstate = m_mainworker.m_trend_calculator[tID].m_state; 9750 } 9751 root["result"][ii]["trend"] = (int)tstate; 9752 } 9753 } 9754 else if (dType == pTypeTEMP_HUM_BARO) 9755 { 9756 std::vector<std::string> strarray; 9757 StringSplit(sValue, ";", strarray); 9758 if (strarray.size() == 5) 9759 { 9760 double tempCelcius = atof(strarray[0].c_str()); 9761 double temp = ConvertTemperature(tempCelcius, tempsign); 9762 int humidity = atoi(strarray[1].c_str()); 9763 9764 root["result"][ii]["Temp"] = temp; 9765 root["result"][ii]["Humidity"] = humidity; 9766 root["result"][ii]["HumidityStatus"] = RFX_Humidity_Status_Desc(atoi(strarray[2].c_str())); 9767 root["result"][ii]["Forecast"] = atoi(strarray[4].c_str()); 9768 9769 sprintf(szTmp, "%.2f", ConvertTemperature(CalculateDewPoint(tempCelcius, humidity), tempsign)); 9770 root["result"][ii]["DewPoint"] = szTmp; 9771 9772 if (dSubType == sTypeTHBFloat) 9773 { 9774 root["result"][ii]["Barometer"] = atof(strarray[3].c_str()); 9775 root["result"][ii]["ForecastStr"] = RFX_WSForecast_Desc(atoi(strarray[4].c_str())); 9776 } 9777 else 9778 { 9779 root["result"][ii]["Barometer"] = atoi(strarray[3].c_str()); 9780 root["result"][ii]["ForecastStr"] = RFX_Forecast_Desc(atoi(strarray[4].c_str())); 9781 } 9782 if (dSubType == sTypeTHBFloat) 9783 { 9784 sprintf(szData, "%.1f %c, %d %%, %.1f hPa", 9785 temp, 9786 tempsign, 9787 atoi(strarray[1].c_str()), 9788 atof(strarray[3].c_str()) 9789 ); 9790 } 9791 else 9792 { 9793 sprintf(szData, "%.1f %c, %d %%, %d hPa", 9794 temp, 9795 tempsign, 9796 atoi(strarray[1].c_str()), 9797 atoi(strarray[3].c_str()) 9798 ); 9799 } 9800 root["result"][ii]["Data"] = szData; 9801 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9802 9803 _tTrendCalculator::_eTendencyType tstate = _tTrendCalculator::_eTendencyType::TENDENCY_UNKNOWN; 9804 uint64_t tID = ((uint64_t)(hardwareID & 0x7FFFFFFF) << 32) | (devIdx & 0x7FFFFFFF); 9805 if (m_mainworker.m_trend_calculator.find(tID) != m_mainworker.m_trend_calculator.end()) 9806 { 9807 tstate = m_mainworker.m_trend_calculator[tID].m_state; 9808 } 9809 root["result"][ii]["trend"] = (int)tstate; 9810 } 9811 } 9812 else if (dType == pTypeTEMP_BARO) 9813 { 9814 std::vector<std::string> strarray; 9815 StringSplit(sValue, ";", strarray); 9816 if (strarray.size() >= 3) 9817 { 9818 double tvalue = ConvertTemperature(atof(strarray[0].c_str()), tempsign); 9819 root["result"][ii]["Temp"] = tvalue; 9820 int forecast = atoi(strarray[2].c_str()); 9821 root["result"][ii]["Forecast"] = forecast; 9822 root["result"][ii]["ForecastStr"] = BMP_Forecast_Desc(forecast); 9823 root["result"][ii]["Barometer"] = atof(strarray[1].c_str()); 9824 9825 sprintf(szData, "%.1f %c, %.1f hPa", 9826 tvalue, 9827 tempsign, 9828 atof(strarray[1].c_str()) 9829 ); 9830 root["result"][ii]["Data"] = szData; 9831 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9832 9833 _tTrendCalculator::_eTendencyType tstate = _tTrendCalculator::_eTendencyType::TENDENCY_UNKNOWN; 9834 uint64_t tID = ((uint64_t)(hardwareID & 0x7FFFFFFF) << 32) | (devIdx & 0x7FFFFFFF); 9835 if (m_mainworker.m_trend_calculator.find(tID) != m_mainworker.m_trend_calculator.end()) 9836 { 9837 tstate = m_mainworker.m_trend_calculator[tID].m_state; 9838 } 9839 root["result"][ii]["trend"] = (int)tstate; 9840 } 9841 } 9842 else if (dType == pTypeUV) 9843 { 9844 std::vector<std::string> strarray; 9845 StringSplit(sValue, ";", strarray); 9846 if (strarray.size() == 2) 9847 { 9848 float UVI = static_cast<float>(atof(strarray[0].c_str())); 9849 root["result"][ii]["UVI"] = strarray[0]; 9850 if (dSubType == sTypeUV3) 9851 { 9852 double tvalue = ConvertTemperature(atof(strarray[1].c_str()), tempsign); 9853 9854 root["result"][ii]["Temp"] = tvalue; 9855 sprintf(szData, "%.1f UVI, %.1f° %c", UVI, tvalue, tempsign); 9856 9857 _tTrendCalculator::_eTendencyType tstate = _tTrendCalculator::_eTendencyType::TENDENCY_UNKNOWN; 9858 uint64_t tID = ((uint64_t)(hardwareID & 0x7FFFFFFF) << 32) | (devIdx & 0x7FFFFFFF); 9859 if (m_mainworker.m_trend_calculator.find(tID) != m_mainworker.m_trend_calculator.end()) 9860 { 9861 tstate = m_mainworker.m_trend_calculator[tID].m_state; 9862 } 9863 root["result"][ii]["trend"] = (int)tstate; 9864 } 9865 else 9866 { 9867 sprintf(szData, "%.1f UVI", UVI); 9868 } 9869 root["result"][ii]["Data"] = szData; 9870 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9871 } 9872 } 9873 else if (dType == pTypeWIND) 9874 { 9875 std::vector<std::string> strarray; 9876 StringSplit(sValue, ";", strarray); 9877 if (strarray.size() == 6) 9878 { 9879 root["result"][ii]["Direction"] = atof(strarray[0].c_str()); 9880 root["result"][ii]["DirectionStr"] = strarray[1]; 9881 9882 if (dSubType != sTypeWIND5) 9883 { 9884 int intSpeed = atoi(strarray[2].c_str()); 9885 if (m_sql.m_windunit != WINDUNIT_Beaufort) 9886 { 9887 sprintf(szTmp, "%.1f", float(intSpeed) * m_sql.m_windscale); 9888 } 9889 else 9890 { 9891 float windms = float(intSpeed) * 0.1f; 9892 sprintf(szTmp, "%d", MStoBeaufort(windms)); 9893 } 9894 root["result"][ii]["Speed"] = szTmp; 9895 } 9896 9897 //if (dSubType!=sTypeWIND6) //problem in RFXCOM firmware? gust=speed? 9898 { 9899 int intGust = atoi(strarray[3].c_str()); 9900 if (m_sql.m_windunit != WINDUNIT_Beaufort) 9901 { 9902 sprintf(szTmp, "%.1f", float(intGust) *m_sql.m_windscale); 9903 } 9904 else 9905 { 9906 float gustms = float(intGust) * 0.1f; 9907 sprintf(szTmp, "%d", MStoBeaufort(gustms)); 9908 } 9909 root["result"][ii]["Gust"] = szTmp; 9910 } 9911 if ((dSubType == sTypeWIND4) || (dSubType == sTypeWINDNoTemp)) 9912 { 9913 if (dSubType == sTypeWIND4) 9914 { 9915 double tvalue = ConvertTemperature(atof(strarray[4].c_str()), tempsign); 9916 root["result"][ii]["Temp"] = tvalue; 9917 } 9918 double tvalue = ConvertTemperature(atof(strarray[5].c_str()), tempsign); 9919 root["result"][ii]["Chill"] = tvalue; 9920 9921 _tTrendCalculator::_eTendencyType tstate = _tTrendCalculator::_eTendencyType::TENDENCY_UNKNOWN; 9922 uint64_t tID = ((uint64_t)(hardwareID & 0x7FFFFFFF) << 32) | (devIdx & 0x7FFFFFFF); 9923 if (m_mainworker.m_trend_calculator.find(tID) != m_mainworker.m_trend_calculator.end()) 9924 { 9925 tstate = m_mainworker.m_trend_calculator[tID].m_state; 9926 } 9927 root["result"][ii]["trend"] = (int)tstate; 9928 } 9929 root["result"][ii]["Data"] = sValue; 9930 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9931 } 9932 } 9933 else if (dType == pTypeRAIN) 9934 { 9935 std::vector<std::string> strarray; 9936 StringSplit(sValue, ";", strarray); 9937 if (strarray.size() == 2) 9938 { 9939 //get lowest value of today, and max rate 9940 time_t now = mytime(NULL); 9941 struct tm ltime; 9942 localtime_r(&now, <ime); 9943 char szDate[40]; 9944 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday); 9945 9946 std::vector<std::vector<std::string> > result2; 9947 9948 if (dSubType == sTypeRAINWU || dSubType == sTypeRAINByRate) 9949 { 9950 result2 = m_sql.safe_query( 9951 "SELECT Total, Rate FROM Rain WHERE (DeviceRowID='%q' AND Date>='%q') ORDER BY ROWID DESC LIMIT 1", sd[0].c_str(), szDate); 9952 } 9953 else 9954 { 9955 result2 = m_sql.safe_query( 9956 "SELECT MIN(Total), MAX(Total) FROM Rain WHERE (DeviceRowID='%q' AND Date>='%q')", sd[0].c_str(), szDate); 9957 } 9958 9959 if (!result2.empty()) 9960 { 9961 double total_real = 0; 9962 float rate = 0; 9963 std::vector<std::string> sd2 = result2[0]; 9964 9965 if (dSubType == sTypeRAINWU || dSubType == sTypeRAINByRate) 9966 { 9967 total_real = atof(sd2[0].c_str()); 9968 } 9969 else 9970 { 9971 double total_min = atof(sd2[0].c_str()); 9972 double total_max = atof(strarray[1].c_str()); 9973 total_real = total_max - total_min; 9974 } 9975 9976 total_real *= AddjMulti; 9977 if (dSubType == sTypeRAINByRate) 9978 { 9979 rate = static_cast<float>(atof(sd2[1].c_str()) / 10000.0f); 9980 } 9981 else 9982 { 9983 rate = (static_cast<float>(atof(strarray[0].c_str())) / 100.0f)*float(AddjMulti); 9984 } 9985 9986 sprintf(szTmp, "%.1f", total_real); 9987 root["result"][ii]["Rain"] = szTmp; 9988 sprintf(szTmp, "%g", rate); 9989 root["result"][ii]["RainRate"] = szTmp; 9990 root["result"][ii]["Data"] = sValue; 9991 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9992 } 9993 else 9994 { 9995 root["result"][ii]["Rain"] = "0"; 9996 root["result"][ii]["RainRate"] = "0"; 9997 root["result"][ii]["Data"] = "0"; 9998 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 9999 } 10000 } 10001 } 10002 else if (dType == pTypeRFXMeter) 10003 { 10004 std::string ValueQuantity = options["ValueQuantity"]; 10005 std::string ValueUnits = options["ValueUnits"]; 10006 10007 if (ValueQuantity.empty()) { 10008 ValueQuantity.assign("Count"); 10009 } 10010 if (ValueUnits.empty()) { 10011 ValueUnits.assign(""); 10012 } 10013 10014 //get value of today 10015 time_t now = mytime(NULL); 10016 struct tm ltime; 10017 localtime_r(&now, <ime); 10018 char szDate[40]; 10019 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday); 10020 10021 std::vector<std::vector<std::string> > result2; 10022 strcpy(szTmp, "0"); 10023 result2 = m_sql.safe_query("SELECT MIN(Value) FROM Meter WHERE (DeviceRowID='%q' AND Date>='%q')", sd[0].c_str(), szDate); 10024 if (!result2.empty()) 10025 { 10026 std::vector<std::string> sd2 = result2[0]; 10027 10028 uint64_t total_min = std::stoull(sd2[0]); 10029 uint64_t total_max = std::stoull(sValue); 10030 uint64_t total_real = total_max - total_min; 10031 sprintf(szTmp, "%" PRIu64, total_real); 10032 10033 float divider = m_sql.GetCounterDivider(int(metertype), int(dType), float(AddjValue2)); 10034 float musage = 0.0f; 10035 switch (metertype) 10036 { 10037 case MTYPE_ENERGY: 10038 case MTYPE_ENERGY_GENERATED: 10039 musage = float(total_real) / divider; 10040 sprintf(szTmp, "%.3f kWh", musage); 10041 break; 10042 case MTYPE_GAS: 10043 musage = float(total_real) / divider; 10044 sprintf(szTmp, "%.3f m3", musage); 10045 break; 10046 case MTYPE_WATER: 10047 musage = float(total_real) / (divider / 1000.0f); 10048 sprintf(szTmp, "%d Liter", round(musage)); 10049 break; 10050 case MTYPE_COUNTER: 10051 sprintf(szTmp, "%" PRIu64, total_real); 10052 if (!ValueUnits.empty()) 10053 { 10054 strcat(szTmp, " "); 10055 strcat(szTmp, ValueUnits.c_str()); 10056 } 10057 break; 10058 default: 10059 strcpy(szTmp, "?"); 10060 break; 10061 } 10062 } 10063 root["result"][ii]["CounterToday"] = szTmp; 10064 10065 root["result"][ii]["SwitchTypeVal"] = metertype; 10066 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10067 root["result"][ii]["ValueQuantity"] = ""; 10068 root["result"][ii]["ValueUnits"] = ""; 10069 10070 double meteroffset = AddjValue; 10071 float divider = m_sql.GetCounterDivider(int(metertype), int(dType), float(AddjValue2)); 10072 10073 double dvalue = static_cast<double>(atof(sValue.c_str())); 10074 10075 switch (metertype) 10076 { 10077 case MTYPE_ENERGY: 10078 case MTYPE_ENERGY_GENERATED: 10079 sprintf(szTmp, "%.3f kWh", meteroffset + (dvalue / divider)); 10080 root["result"][ii]["Data"] = szTmp; 10081 root["result"][ii]["Counter"] = szTmp; 10082 break; 10083 case MTYPE_GAS: 10084 sprintf(szTmp, "%.3f m3", meteroffset + (dvalue / divider)); 10085 root["result"][ii]["Data"] = szTmp; 10086 root["result"][ii]["Counter"] = szTmp; 10087 break; 10088 case MTYPE_WATER: 10089 sprintf(szTmp, "%.3f m3", meteroffset + (dvalue / divider)); 10090 root["result"][ii]["Data"] = szTmp; 10091 root["result"][ii]["Counter"] = szTmp; 10092 break; 10093 case MTYPE_COUNTER: 10094 sprintf(szTmp, "%g %s", meteroffset + dvalue, ValueUnits.c_str()); 10095 root["result"][ii]["Data"] = szTmp; 10096 root["result"][ii]["Counter"] = szTmp; 10097 root["result"][ii]["ValueQuantity"] = ValueQuantity; 10098 root["result"][ii]["ValueUnits"] = ValueUnits; 10099 break; 10100 default: 10101 root["result"][ii]["Data"] = "?"; 10102 root["result"][ii]["Counter"] = "?"; 10103 root["result"][ii]["ValueQuantity"] = ValueQuantity; 10104 root["result"][ii]["ValueUnits"] = ValueUnits; 10105 break; 10106 } 10107 } 10108 else if ((dType == pTypeGeneral) && (dSubType == sTypeCounterIncremental)) 10109 { 10110 std::string ValueQuantity = options["ValueQuantity"]; 10111 std::string ValueUnits = options["ValueUnits"]; 10112 if (ValueQuantity.empty()) { 10113 ValueQuantity.assign("Count"); 10114 } 10115 if (ValueUnits.empty()) { 10116 ValueUnits.assign(""); 10117 } 10118 float divider = m_sql.GetCounterDivider(int(metertype), int(dType), float(AddjValue2)); 10119 10120 //get value of today 10121 time_t now = mytime(NULL); 10122 struct tm ltime; 10123 localtime_r(&now, <ime); 10124 char szDate[40]; 10125 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday); 10126 10127 std::vector<std::vector<std::string> > result2; 10128 strcpy(szTmp, "0"); 10129 result2 = m_sql.safe_query("SELECT MIN(Value) FROM Meter WHERE (DeviceRowID='%q' AND Date>='%q')", sd[0].c_str(), szDate); 10130 if (!result2.empty()) 10131 { 10132 std::vector<std::string> sd2 = result2[0]; 10133 10134 uint64_t total_min = std::stoull(sd2[0]); 10135 uint64_t total_max = std::stoull(sValue); 10136 uint64_t total_real = total_max - total_min; 10137 sprintf(szTmp, "%" PRIu64, total_real); 10138 10139 float musage = 0; 10140 switch (metertype) 10141 { 10142 case MTYPE_ENERGY: 10143 case MTYPE_ENERGY_GENERATED: 10144 musage = float(total_real) / divider; 10145 sprintf(szTmp, "%.3f kWh", musage); 10146 break; 10147 case MTYPE_GAS: 10148 musage = float(total_real) / divider; 10149 sprintf(szTmp, "%.3f m3", musage); 10150 break; 10151 case MTYPE_WATER: 10152 musage = float(total_real) / divider; 10153 sprintf(szTmp, "%.3f m3", musage); 10154 break; 10155 case MTYPE_COUNTER: 10156 sprintf(szTmp, "%" PRIu64, total_real); 10157 if (!ValueUnits.empty()) 10158 { 10159 strcat(szTmp, " "); 10160 strcat(szTmp, ValueUnits.c_str()); 10161 } 10162 break; 10163 default: 10164 strcpy(szTmp, "0"); 10165 break; 10166 } 10167 } 10168 root["result"][ii]["Counter"] = sValue; 10169 root["result"][ii]["CounterToday"] = szTmp; 10170 root["result"][ii]["SwitchTypeVal"] = metertype; 10171 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10172 root["result"][ii]["TypeImg"] = "counter"; 10173 root["result"][ii]["ValueQuantity"] = ""; 10174 root["result"][ii]["ValueUnits"] = ""; 10175 double dvalue = static_cast<double>(atof(sValue.c_str())); 10176 double meteroffset = AddjValue; 10177 10178 switch (metertype) 10179 { 10180 case MTYPE_ENERGY: 10181 case MTYPE_ENERGY_GENERATED: 10182 sprintf(szTmp, "%.3f kWh", meteroffset + (dvalue / divider)); 10183 root["result"][ii]["Data"] = szTmp; 10184 root["result"][ii]["Counter"] = szTmp; 10185 break; 10186 case MTYPE_GAS: 10187 sprintf(szTmp, "%.3f m3", meteroffset + (dvalue / divider)); 10188 root["result"][ii]["Data"] = szTmp; 10189 root["result"][ii]["Counter"] = szTmp; 10190 break; 10191 case MTYPE_WATER: 10192 sprintf(szTmp, "%.3f m3", meteroffset + (dvalue / divider)); 10193 root["result"][ii]["Data"] = szTmp; 10194 root["result"][ii]["Counter"] = szTmp; 10195 break; 10196 case MTYPE_COUNTER: 10197 sprintf(szTmp, "%" PRIu64 " %s", static_cast<uint64_t>(meteroffset + dvalue), ValueUnits.c_str()); 10198 root["result"][ii]["Data"] = szTmp; 10199 root["result"][ii]["Counter"] = szTmp; 10200 root["result"][ii]["ValueQuantity"] = ValueQuantity; 10201 root["result"][ii]["ValueUnits"] = ValueUnits; 10202 break; 10203 default: 10204 root["result"][ii]["Data"] = "?"; 10205 root["result"][ii]["Counter"] = "?"; 10206 root["result"][ii]["ValueQuantity"] = ValueQuantity; 10207 root["result"][ii]["ValueUnits"] = ValueUnits; 10208 break; 10209 } 10210 } 10211 else if ((dType == pTypeGeneral) && (dSubType == sTypeManagedCounter)) 10212 { 10213 std::string ValueQuantity = options["ValueQuantity"]; 10214 std::string ValueUnits = options["ValueUnits"]; 10215 if (ValueQuantity.empty()) { 10216 ValueQuantity.assign("Count"); 10217 } 10218 if (ValueUnits.empty()) { 10219 ValueUnits.assign(""); 10220 } 10221 float divider = m_sql.GetCounterDivider(int(metertype), int(dType), float(AddjValue2)); 10222 10223 std::vector<std::string> splitresults; 10224 StringSplit(sValue, ";", splitresults); 10225 double dvalue; 10226 if (splitresults.size() < 2) { 10227 dvalue = static_cast<double>(atof(sValue.c_str())); 10228 } 10229 else { 10230 dvalue = static_cast<double>(atof(splitresults[1].c_str())); 10231 if (dvalue < 0.0) { 10232 dvalue = static_cast<double>(atof(splitresults[0].c_str())); 10233 } 10234 } 10235 root["result"][ii]["Data"] = root["result"][ii]["Counter"]; 10236 10237 root["result"][ii]["SwitchTypeVal"] = metertype; 10238 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10239 root["result"][ii]["TypeImg"] = "counter"; 10240 root["result"][ii]["ValueQuantity"] = ""; 10241 root["result"][ii]["ValueUnits"] = ""; 10242 root["result"][ii]["ShowNotifications"] = false; 10243 double meteroffset = AddjValue; 10244 10245 switch (metertype) 10246 { 10247 case MTYPE_ENERGY: 10248 case MTYPE_ENERGY_GENERATED: 10249 sprintf(szTmp, "%.3f kWh", meteroffset + (dvalue / divider)); 10250 root["result"][ii]["Data"] = szTmp; 10251 root["result"][ii]["Counter"] = szTmp; 10252 break; 10253 case MTYPE_GAS: 10254 sprintf(szTmp, "%.3f m3", meteroffset + (dvalue / divider)); 10255 root["result"][ii]["Data"] = szTmp; 10256 root["result"][ii]["Counter"] = szTmp; 10257 break; 10258 case MTYPE_WATER: 10259 sprintf(szTmp, "%.3f m3", meteroffset + (dvalue / divider)); 10260 root["result"][ii]["Data"] = szTmp; 10261 root["result"][ii]["Counter"] = szTmp; 10262 break; 10263 case MTYPE_COUNTER: 10264 sprintf(szTmp, "%g %s", meteroffset + dvalue, ValueUnits.c_str()); 10265 root["result"][ii]["Data"] = szTmp; 10266 root["result"][ii]["Counter"] = szTmp; 10267 root["result"][ii]["ValueQuantity"] = ValueQuantity; 10268 root["result"][ii]["ValueUnits"] = ValueUnits; 10269 break; 10270 default: 10271 root["result"][ii]["Data"] = "?"; 10272 root["result"][ii]["Counter"] = "?"; 10273 root["result"][ii]["ValueQuantity"] = ValueQuantity; 10274 root["result"][ii]["ValueUnits"] = ValueUnits; 10275 break; 10276 } 10277 } 10278 else if (dType == pTypeYouLess) 10279 { 10280 std::string ValueQuantity = options["ValueQuantity"]; 10281 std::string ValueUnits = options["ValueUnits"]; 10282 float musage = 0; 10283 if (ValueQuantity.empty()) { 10284 ValueQuantity.assign("Count"); 10285 } 10286 if (ValueUnits.empty()) { 10287 ValueUnits.assign(""); 10288 } 10289 float divider = m_sql.GetCounterDivider(int(metertype), int(dType), float(AddjValue2)); 10290 10291 //get value of today 10292 time_t now = mytime(NULL); 10293 struct tm ltime; 10294 localtime_r(&now, <ime); 10295 char szDate[40]; 10296 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday); 10297 10298 std::vector<std::vector<std::string> > result2; 10299 strcpy(szTmp, "0"); 10300 result2 = m_sql.safe_query("SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID='%q' AND Date>='%q')", sd[0].c_str(), szDate); 10301 if (!result2.empty()) 10302 { 10303 std::vector<std::string> sd2 = result2[0]; 10304 10305 unsigned long long total_min = std::strtoull(sd2[0].c_str(), nullptr, 10); 10306 unsigned long long total_max = std::strtoull(sd2[1].c_str(), nullptr, 10); 10307 unsigned long long total_real; 10308 10309 total_real = total_max - total_min; 10310 sprintf(szTmp, "%llu", total_real); 10311 10312 musage = 0; 10313 switch (metertype) 10314 { 10315 case MTYPE_ENERGY: 10316 case MTYPE_ENERGY_GENERATED: 10317 musage = float(total_real) / divider; 10318 sprintf(szTmp, "%.3f kWh", musage); 10319 break; 10320 case MTYPE_GAS: 10321 musage = float(total_real) / divider; 10322 sprintf(szTmp, "%.3f m3", musage); 10323 break; 10324 case MTYPE_WATER: 10325 musage = float(total_real) / divider; 10326 sprintf(szTmp, "%.3f m3", musage); 10327 break; 10328 case MTYPE_COUNTER: 10329 sprintf(szTmp, "%llu %s", total_real, ValueUnits.c_str()); 10330 break; 10331 default: 10332 strcpy(szTmp, "0"); 10333 break; 10334 } 10335 } 10336 root["result"][ii]["CounterToday"] = szTmp; 10337 10338 10339 std::vector<std::string> splitresults; 10340 StringSplit(sValue, ";", splitresults); 10341 if (splitresults.size() < 2) 10342 continue; 10343 10344 unsigned long long total_actual = std::strtoull(splitresults[0].c_str(), nullptr, 10); 10345 musage = 0; 10346 switch (metertype) 10347 { 10348 case MTYPE_ENERGY: 10349 case MTYPE_ENERGY_GENERATED: 10350 musage = float(total_actual) / divider; 10351 sprintf(szTmp, "%.03f", musage); 10352 break; 10353 case MTYPE_GAS: 10354 case MTYPE_WATER: 10355 musage = float(total_actual) / divider; 10356 sprintf(szTmp, "%.03f", musage); 10357 break; 10358 case MTYPE_COUNTER: 10359 sprintf(szTmp, "%llu", total_actual); 10360 break; 10361 default: 10362 strcpy(szTmp, "0"); 10363 break; 10364 } 10365 root["result"][ii]["Counter"] = szTmp; 10366 10367 root["result"][ii]["SwitchTypeVal"] = metertype; 10368 10369 unsigned long long acounter = std::strtoull(sValue.c_str(), nullptr, 10); 10370 musage = 0; 10371 switch (metertype) 10372 { 10373 case MTYPE_ENERGY: 10374 case MTYPE_ENERGY_GENERATED: 10375 musage = float(acounter) / divider; 10376 sprintf(szTmp, "%.3f kWh %s Watt", musage, splitresults[1].c_str()); 10377 break; 10378 case MTYPE_GAS: 10379 musage = float(acounter) / divider; 10380 sprintf(szTmp, "%.3f m3", musage); 10381 break; 10382 case MTYPE_WATER: 10383 musage = float(acounter) / divider; 10384 sprintf(szTmp, "%.3f m3", musage); 10385 break; 10386 case MTYPE_COUNTER: 10387 sprintf(szTmp, "%llu %s", acounter, ValueUnits.c_str()); 10388 break; 10389 default: 10390 strcpy(szTmp, "0"); 10391 break; 10392 } 10393 root["result"][ii]["Data"] = szTmp; 10394 root["result"][ii]["ValueQuantity"] = ""; 10395 root["result"][ii]["ValueUnits"] = ""; 10396 switch (metertype) 10397 { 10398 case MTYPE_ENERGY: 10399 case MTYPE_ENERGY_GENERATED: 10400 sprintf(szTmp, "%s Watt", splitresults[1].c_str()); 10401 break; 10402 case MTYPE_GAS: 10403 sprintf(szTmp, "%s m3", splitresults[1].c_str()); 10404 break; 10405 case MTYPE_WATER: 10406 sprintf(szTmp, "%s m3", splitresults[1].c_str()); 10407 break; 10408 case MTYPE_COUNTER: 10409 sprintf(szTmp, "%s", splitresults[1].c_str()); 10410 root["result"][ii]["ValueQuantity"] = ValueQuantity; 10411 root["result"][ii]["ValueUnits"] = ValueUnits; 10412 break; 10413 default: 10414 strcpy(szTmp, "0"); 10415 break; 10416 } 10417 10418 root["result"][ii]["Usage"] = szTmp; 10419 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10420 } 10421 else if (dType == pTypeP1Power) 10422 { 10423 std::vector<std::string> splitresults; 10424 StringSplit(sValue, ";", splitresults); 10425 if (splitresults.size() != 6) 10426 { 10427 root["result"][ii]["SwitchTypeVal"] = MTYPE_ENERGY; 10428 root["result"][ii]["Counter"] = "0"; 10429 root["result"][ii]["CounterDeliv"] = "0"; 10430 root["result"][ii]["Usage"] = "Invalid"; 10431 root["result"][ii]["UsageDeliv"] = "Invalid"; 10432 root["result"][ii]["Data"] = "Invalid!: " + sValue; 10433 root["result"][ii]["HaveTimeout"] = true; 10434 root["result"][ii]["CounterToday"] = "Invalid"; 10435 root["result"][ii]["CounterDelivToday"] = "Invalid"; 10436 } 10437 else 10438 { 10439 float EnergyDivider = 1000.0f; 10440 int tValue; 10441 if (m_sql.GetPreferencesVar("MeterDividerEnergy", tValue)) 10442 { 10443 EnergyDivider = float(tValue); 10444 } 10445 10446 unsigned long long powerusage1 = std::strtoull(splitresults[0].c_str(), nullptr, 10); 10447 unsigned long long powerusage2 = std::strtoull(splitresults[1].c_str(), nullptr, 10); 10448 unsigned long long powerdeliv1 = std::strtoull(splitresults[2].c_str(), nullptr, 10); 10449 unsigned long long powerdeliv2 = std::strtoull(splitresults[3].c_str(), nullptr, 10); 10450 unsigned long long usagecurrent = std::strtoull(splitresults[4].c_str(), nullptr, 10); 10451 unsigned long long delivcurrent = std::strtoull(splitresults[5].c_str(), nullptr, 10); 10452 10453 powerdeliv1 = (powerdeliv1 < 10) ? 0 : powerdeliv1; 10454 powerdeliv2 = (powerdeliv2 < 10) ? 0 : powerdeliv2; 10455 10456 unsigned long long powerusage = powerusage1 + powerusage2; 10457 unsigned long long powerdeliv = powerdeliv1 + powerdeliv2; 10458 if (powerdeliv < 2) 10459 powerdeliv = 0; 10460 10461 double musage = 0; 10462 10463 root["result"][ii]["SwitchTypeVal"] = MTYPE_ENERGY; 10464 musage = double(powerusage) / EnergyDivider; 10465 sprintf(szTmp, "%.03f", musage); 10466 root["result"][ii]["Counter"] = szTmp; 10467 musage = double(powerdeliv) / EnergyDivider; 10468 sprintf(szTmp, "%.03f", musage); 10469 root["result"][ii]["CounterDeliv"] = szTmp; 10470 10471 if (bHaveTimeout) 10472 { 10473 usagecurrent = 0; 10474 delivcurrent = 0; 10475 } 10476 sprintf(szTmp, "%llu Watt", usagecurrent); 10477 root["result"][ii]["Usage"] = szTmp; 10478 sprintf(szTmp, "%llu Watt", delivcurrent); 10479 root["result"][ii]["UsageDeliv"] = szTmp; 10480 root["result"][ii]["Data"] = sValue; 10481 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10482 10483 //get value of today 10484 time_t now = mytime(NULL); 10485 struct tm ltime; 10486 localtime_r(&now, <ime); 10487 char szDate[40]; 10488 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday); 10489 10490 std::vector<std::vector<std::string> > result2; 10491 strcpy(szTmp, "0"); 10492 result2 = m_sql.safe_query("SELECT MIN(Value1), MIN(Value2), MIN(Value5), MIN(Value6) FROM MultiMeter WHERE (DeviceRowID='%q' AND Date>='%q')", 10493 sd[0].c_str(), szDate); 10494 if (!result2.empty()) 10495 { 10496 std::vector<std::string> sd2 = result2[0]; 10497 10498 unsigned long long total_min_usage_1 = std::strtoull(sd2[0].c_str(), nullptr, 10); 10499 unsigned long long total_min_deliv_1 = std::strtoull(sd2[1].c_str(), nullptr, 10); 10500 unsigned long long total_min_usage_2 = std::strtoull(sd2[2].c_str(), nullptr, 10); 10501 unsigned long long total_min_deliv_2 = std::strtoull(sd2[3].c_str(), nullptr, 10); 10502 unsigned long long total_real_usage, total_real_deliv; 10503 10504 total_real_usage = powerusage - (total_min_usage_1 + total_min_usage_2); 10505 total_real_deliv = powerdeliv - (total_min_deliv_1 + total_min_deliv_2); 10506 10507 musage = double(total_real_usage) / EnergyDivider; 10508 sprintf(szTmp, "%.3f kWh", musage); 10509 root["result"][ii]["CounterToday"] = szTmp; 10510 musage = double(total_real_deliv) / EnergyDivider; 10511 sprintf(szTmp, "%.3f kWh", musage); 10512 root["result"][ii]["CounterDelivToday"] = szTmp; 10513 } 10514 else 10515 { 10516 sprintf(szTmp, "%.3f kWh", 0.0f); 10517 root["result"][ii]["CounterToday"] = szTmp; 10518 root["result"][ii]["CounterDelivToday"] = szTmp; 10519 } 10520 } 10521 } 10522 else if (dType == pTypeP1Gas) 10523 { 10524 root["result"][ii]["SwitchTypeVal"] = MTYPE_GAS; 10525 10526 //get lowest value of today 10527 time_t now = mytime(NULL); 10528 struct tm ltime; 10529 localtime_r(&now, <ime); 10530 char szDate[40]; 10531 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday); 10532 10533 std::vector<std::vector<std::string> > result2; 10534 10535 float divider = m_sql.GetCounterDivider(int(metertype), int(dType), float(AddjValue2)); 10536 10537 strcpy(szTmp, "0"); 10538 result2 = m_sql.safe_query("SELECT MIN(Value) FROM Meter WHERE (DeviceRowID='%q' AND Date>='%q')", 10539 sd[0].c_str(), szDate); 10540 if (!result2.empty()) 10541 { 10542 std::vector<std::string> sd2 = result2[0]; 10543 10544 uint64_t total_min_gas = std::stoull(sd2[0]); 10545 uint64_t gasactual = std::stoull(sValue); 10546 uint64_t total_real_gas = gasactual - total_min_gas; 10547 10548 double musage = double(gasactual) / divider; 10549 sprintf(szTmp, "%.03f", musage); 10550 root["result"][ii]["Counter"] = szTmp; 10551 musage = double(total_real_gas) / divider; 10552 sprintf(szTmp, "%.03f m3", musage); 10553 root["result"][ii]["CounterToday"] = szTmp; 10554 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10555 sprintf(szTmp, "%.03f", atof(sValue.c_str()) / divider); 10556 root["result"][ii]["Data"] = szTmp; 10557 } 10558 else 10559 { 10560 sprintf(szTmp, "%.03f", 0.0f); 10561 root["result"][ii]["Counter"] = szTmp; 10562 sprintf(szTmp, "%.03f m3", 0.0f); 10563 root["result"][ii]["CounterToday"] = szTmp; 10564 sprintf(szTmp, "%.03f", atof(sValue.c_str()) / divider); 10565 root["result"][ii]["Data"] = szTmp; 10566 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10567 } 10568 } 10569 else if (dType == pTypeCURRENT) 10570 { 10571 std::vector<std::string> strarray; 10572 StringSplit(sValue, ";", strarray); 10573 if (strarray.size() == 3) 10574 { 10575 //CM113 10576 int displaytype = 0; 10577 int voltage = 230; 10578 m_sql.GetPreferencesVar("CM113DisplayType", displaytype); 10579 m_sql.GetPreferencesVar("ElectricVoltage", voltage); 10580 10581 double val1 = atof(strarray[0].c_str()); 10582 double val2 = atof(strarray[1].c_str()); 10583 double val3 = atof(strarray[2].c_str()); 10584 10585 if (displaytype == 0) 10586 { 10587 if ((val2 == 0) && (val3 == 0)) 10588 sprintf(szData, "%.1f A", val1); 10589 else 10590 sprintf(szData, "%.1f A, %.1f A, %.1f A", val1, val2, val3); 10591 } 10592 else 10593 { 10594 if ((val2 == 0) && (val3 == 0)) 10595 sprintf(szData, "%d Watt", int(val1*voltage)); 10596 else 10597 sprintf(szData, "%d Watt, %d Watt, %d Watt", int(val1*voltage), int(val2*voltage), int(val3*voltage)); 10598 } 10599 root["result"][ii]["Data"] = szData; 10600 root["result"][ii]["displaytype"] = displaytype; 10601 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10602 } 10603 } 10604 else if (dType == pTypeCURRENTENERGY) 10605 { 10606 std::vector<std::string> strarray; 10607 StringSplit(sValue, ";", strarray); 10608 if (strarray.size() == 4) 10609 { 10610 //CM180i 10611 int displaytype = 0; 10612 int voltage = 230; 10613 m_sql.GetPreferencesVar("CM113DisplayType", displaytype); 10614 m_sql.GetPreferencesVar("ElectricVoltage", voltage); 10615 10616 double total = atof(strarray[3].c_str()); 10617 if (displaytype == 0) 10618 { 10619 sprintf(szData, "%.1f A, %.1f A, %.1f A", atof(strarray[0].c_str()), atof(strarray[1].c_str()), atof(strarray[2].c_str())); 10620 } 10621 else 10622 { 10623 sprintf(szData, "%d Watt, %d Watt, %d Watt", int(atof(strarray[0].c_str())*voltage), int(atof(strarray[1].c_str())*voltage), int(atof(strarray[2].c_str())*voltage)); 10624 } 10625 if (total > 0) 10626 { 10627 sprintf(szTmp, ", Total: %.3f kWh", total / 1000.0f); 10628 strcat(szData, szTmp); 10629 } 10630 root["result"][ii]["Data"] = szData; 10631 root["result"][ii]["displaytype"] = displaytype; 10632 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10633 } 10634 } 10635 else if ( 10636 ((dType == pTypeENERGY) || (dType == pTypePOWER)) || 10637 ((dType == pTypeGeneral) && (dSubType == sTypeKwh)) 10638 ) 10639 { 10640 std::vector<std::string> strarray; 10641 StringSplit(sValue, ";", strarray); 10642 if (strarray.size() == 2) 10643 { 10644 double total = atof(strarray[1].c_str()) / 1000; 10645 10646 time_t now = mytime(NULL); 10647 struct tm ltime; 10648 localtime_r(&now, <ime); 10649 char szDate[40]; 10650 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday); 10651 10652 std::vector<std::vector<std::string> > result2; 10653 strcpy(szTmp, "0"); 10654 result2 = m_sql.safe_query("SELECT MIN(Value) FROM Meter WHERE (DeviceRowID='%q' AND Date>='%q')", 10655 sd[0].c_str(), szDate); 10656 if (!result2.empty()) 10657 { 10658 float divider = m_sql.GetCounterDivider(int(metertype), int(dType), float(AddjValue2)); 10659 10660 std::vector<std::string> sd2 = result2[0]; 10661 double minimum = atof(sd2[0].c_str()) / divider; 10662 10663 sprintf(szData, "%.3f kWh", total); 10664 root["result"][ii]["Data"] = szData; 10665 if ((dType == pTypeENERGY) || (dType == pTypePOWER)) 10666 { 10667 sprintf(szData, "%ld Watt", atol(strarray[0].c_str())); 10668 } 10669 else 10670 { 10671 sprintf(szData, "%g Watt", atof(strarray[0].c_str())); 10672 } 10673 root["result"][ii]["Usage"] = szData; 10674 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10675 sprintf(szTmp, "%.3f kWh", total - minimum); 10676 root["result"][ii]["CounterToday"] = szTmp; 10677 } 10678 else 10679 { 10680 sprintf(szData, "%.3f kWh", total); 10681 root["result"][ii]["Data"] = szData; 10682 if ((dType == pTypeENERGY) || (dType == pTypePOWER)) 10683 { 10684 sprintf(szData, "%ld Watt", atol(strarray[0].c_str())); 10685 } 10686 else 10687 { 10688 sprintf(szData, "%g Watt", atof(strarray[0].c_str())); 10689 } 10690 root["result"][ii]["Usage"] = szData; 10691 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10692 sprintf(szTmp, "%d kWh", 0); 10693 root["result"][ii]["CounterToday"] = szTmp; 10694 } 10695 root["result"][ii]["TypeImg"] = "current"; 10696 root["result"][ii]["SwitchTypeVal"] = switchtype; //MTYPE_ENERGY 10697 root["result"][ii]["EnergyMeterMode"] = options["EnergyMeterMode"]; //for alternate Energy Reading 10698 } 10699 } 10700 else if (dType == pTypeAirQuality) 10701 { 10702 if (bHaveTimeout) 10703 nValue = 0; 10704 sprintf(szTmp, "%d ppm", nValue); 10705 root["result"][ii]["Data"] = szTmp; 10706 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10707 int airquality = nValue; 10708 if (airquality < 700) 10709 root["result"][ii]["Quality"] = "Excellent"; 10710 else if (airquality < 900) 10711 root["result"][ii]["Quality"] = "Good"; 10712 else if (airquality < 1100) 10713 root["result"][ii]["Quality"] = "Fair"; 10714 else if (airquality < 1600) 10715 root["result"][ii]["Quality"] = "Mediocre"; 10716 else 10717 root["result"][ii]["Quality"] = "Bad"; 10718 } 10719 else if (dType == pTypeThermostat) 10720 { 10721 if (dSubType == sTypeThermSetpoint) 10722 { 10723 bHasTimers = m_sql.HasTimers(sd[0]); 10724 10725 double tempCelcius = atof(sValue.c_str()); 10726 double temp = ConvertTemperature(tempCelcius, tempsign); 10727 10728 sprintf(szTmp, "%.1f", temp); 10729 root["result"][ii]["Data"] = szTmp; 10730 root["result"][ii]["SetPoint"] = szTmp; 10731 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10732 root["result"][ii]["TypeImg"] = "override_mini"; 10733 } 10734 } 10735 else if (dType == pTypeRadiator1) 10736 { 10737 if (dSubType == sTypeSmartwares) 10738 { 10739 bHasTimers = m_sql.HasTimers(sd[0]); 10740 10741 double tempCelcius = atof(sValue.c_str()); 10742 double temp = ConvertTemperature(tempCelcius, tempsign); 10743 10744 sprintf(szTmp, "%.1f", temp); 10745 root["result"][ii]["Data"] = szTmp; 10746 root["result"][ii]["SetPoint"] = szTmp; 10747 root["result"][ii]["HaveTimeout"] = false; //this device does not provide feedback, so no timeout! 10748 root["result"][ii]["TypeImg"] = "override_mini"; 10749 } 10750 } 10751 else if (dType == pTypeGeneral) 10752 { 10753 if (dSubType == sTypeVisibility) 10754 { 10755 float vis = static_cast<float>(atof(sValue.c_str())); 10756 if (metertype == 0) 10757 { 10758 //km 10759 sprintf(szTmp, "%.1f km", vis); 10760 } 10761 else 10762 { 10763 //miles 10764 sprintf(szTmp, "%.1f mi", vis*0.6214f); 10765 } 10766 root["result"][ii]["Data"] = szTmp; 10767 root["result"][ii]["Visibility"] = atof(sValue.c_str()); 10768 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10769 root["result"][ii]["TypeImg"] = "visibility"; 10770 root["result"][ii]["SwitchTypeVal"] = metertype; 10771 } 10772 else if (dSubType == sTypeDistance) 10773 { 10774 float vis = static_cast<float>(atof(sValue.c_str())); 10775 if (metertype == 0) 10776 { 10777 //Metric 10778 sprintf(szTmp, "%.1f cm", vis); 10779 } 10780 else 10781 { 10782 //Imperial 10783 sprintf(szTmp, "%.1f in", vis*0.6214f); 10784 } 10785 root["result"][ii]["Data"] = szTmp; 10786 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10787 root["result"][ii]["TypeImg"] = "visibility"; 10788 root["result"][ii]["SwitchTypeVal"] = metertype; 10789 } 10790 else if (dSubType == sTypeSolarRadiation) 10791 { 10792 float radiation = static_cast<float>(atof(sValue.c_str())); 10793 sprintf(szTmp, "%.1f Watt/m2", radiation); 10794 root["result"][ii]["Data"] = szTmp; 10795 root["result"][ii]["Radiation"] = atof(sValue.c_str()); 10796 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10797 root["result"][ii]["TypeImg"] = "radiation"; 10798 root["result"][ii]["SwitchTypeVal"] = metertype; 10799 } 10800 else if (dSubType == sTypeSoilMoisture) 10801 { 10802 sprintf(szTmp, "%d cb", nValue); 10803 root["result"][ii]["Data"] = szTmp; 10804 root["result"][ii]["Desc"] = Get_Moisture_Desc(nValue); 10805 root["result"][ii]["TypeImg"] = "moisture"; 10806 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10807 root["result"][ii]["SwitchTypeVal"] = metertype; 10808 } 10809 else if (dSubType == sTypeLeafWetness) 10810 { 10811 sprintf(szTmp, "%d", nValue); 10812 root["result"][ii]["Data"] = szTmp; 10813 root["result"][ii]["TypeImg"] = "leaf"; 10814 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10815 root["result"][ii]["SwitchTypeVal"] = metertype; 10816 } 10817 else if (dSubType == sTypeSystemTemp) 10818 { 10819 double tvalue = ConvertTemperature(atof(sValue.c_str()), tempsign); 10820 root["result"][ii]["Temp"] = tvalue; 10821 sprintf(szData, "%.1f %c", tvalue, tempsign); 10822 root["result"][ii]["Data"] = szData; 10823 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10824 root["result"][ii]["Image"] = "Computer"; 10825 root["result"][ii]["TypeImg"] = "temperature"; 10826 root["result"][ii]["Type"] = "temperature"; 10827 _tTrendCalculator::_eTendencyType tstate = _tTrendCalculator::_eTendencyType::TENDENCY_UNKNOWN; 10828 uint64_t tID = ((uint64_t)(hardwareID & 0x7FFFFFFF) << 32) | (devIdx & 0x7FFFFFFF); 10829 if (m_mainworker.m_trend_calculator.find(tID) != m_mainworker.m_trend_calculator.end()) 10830 { 10831 tstate = m_mainworker.m_trend_calculator[tID].m_state; 10832 } 10833 root["result"][ii]["trend"] = (int)tstate; 10834 } 10835 else if (dSubType == sTypePercentage) 10836 { 10837 sprintf(szData, "%g%%", atof(sValue.c_str())); 10838 root["result"][ii]["Data"] = szData; 10839 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10840 root["result"][ii]["Image"] = "Computer"; 10841 root["result"][ii]["TypeImg"] = "hardware"; 10842 } 10843 else if (dSubType == sTypeWaterflow) 10844 { 10845 sprintf(szData, "%g l/min", atof(sValue.c_str())); 10846 root["result"][ii]["Data"] = szData; 10847 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10848 root["result"][ii]["Image"] = "Moisture"; 10849 root["result"][ii]["TypeImg"] = "moisture"; 10850 } 10851 else if (dSubType == sTypeCustom) 10852 { 10853 std::string szAxesLabel = ""; 10854 int SensorType = 1; 10855 std::vector<std::string> sResults; 10856 StringSplit(sOptions, ";", sResults); 10857 10858 if (sResults.size() == 2) 10859 { 10860 SensorType = atoi(sResults[0].c_str()); 10861 szAxesLabel = sResults[1]; 10862 } 10863 sprintf(szData, "%g %s", atof(sValue.c_str()), szAxesLabel.c_str()); 10864 root["result"][ii]["Data"] = szData; 10865 root["result"][ii]["SensorType"] = SensorType; 10866 root["result"][ii]["SensorUnit"] = szAxesLabel; 10867 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10868 10869 std::string IconFile = "Custom"; 10870 if (CustomImage != 0) 10871 { 10872 std::map<int, int>::const_iterator ittIcon = m_custom_light_icons_lookup.find(CustomImage); 10873 if (ittIcon != m_custom_light_icons_lookup.end()) 10874 { 10875 IconFile = m_custom_light_icons[ittIcon->second].RootFile; 10876 } 10877 } 10878 root["result"][ii]["Image"] = IconFile; 10879 root["result"][ii]["TypeImg"] = IconFile; 10880 } 10881 else if (dSubType == sTypeFan) 10882 { 10883 sprintf(szData, "%d RPM", atoi(sValue.c_str())); 10884 root["result"][ii]["Data"] = szData; 10885 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10886 root["result"][ii]["Image"] = "Fan"; 10887 root["result"][ii]["TypeImg"] = "Fan"; 10888 } 10889 else if (dSubType == sTypeSoundLevel) 10890 { 10891 sprintf(szData, "%d dB", atoi(sValue.c_str())); 10892 root["result"][ii]["Data"] = szData; 10893 root["result"][ii]["TypeImg"] = "Speaker"; 10894 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10895 } 10896 else if (dSubType == sTypeVoltage) 10897 { 10898 sprintf(szData, "%g V", atof(sValue.c_str())); 10899 root["result"][ii]["Data"] = szData; 10900 root["result"][ii]["TypeImg"] = "current"; 10901 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10902 root["result"][ii]["Voltage"] = atof(sValue.c_str()); 10903 } 10904 else if (dSubType == sTypeCurrent) 10905 { 10906 sprintf(szData, "%g A", atof(sValue.c_str())); 10907 root["result"][ii]["Data"] = szData; 10908 root["result"][ii]["TypeImg"] = "current"; 10909 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10910 root["result"][ii]["Current"] = atof(sValue.c_str()); 10911 } 10912 else if (dSubType == sTypeTextStatus) 10913 { 10914 root["result"][ii]["Data"] = sValue; 10915 root["result"][ii]["TypeImg"] = "text"; 10916 root["result"][ii]["HaveTimeout"] = false; 10917 root["result"][ii]["ShowNotifications"] = false; 10918 } 10919 else if (dSubType == sTypeAlert) 10920 { 10921 if (nValue > 4) 10922 nValue = 4; 10923 sprintf(szData, "Level: %d", nValue); 10924 root["result"][ii]["Data"] = szData; 10925 if (!sValue.empty()) 10926 root["result"][ii]["Data"] = sValue; 10927 else 10928 root["result"][ii]["Data"] = Get_Alert_Desc(nValue); 10929 root["result"][ii]["TypeImg"] = "Alert"; 10930 root["result"][ii]["Level"] = nValue; 10931 root["result"][ii]["HaveTimeout"] = false; 10932 } 10933 else if (dSubType == sTypePressure) 10934 { 10935 sprintf(szData, "%.1f Bar", atof(sValue.c_str())); 10936 root["result"][ii]["Data"] = szData; 10937 root["result"][ii]["TypeImg"] = "gauge"; 10938 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10939 root["result"][ii]["Pressure"] = atof(sValue.c_str()); 10940 } 10941 else if (dSubType == sTypeBaro) 10942 { 10943 std::vector<std::string> tstrarray; 10944 StringSplit(sValue, ";", tstrarray); 10945 if (tstrarray.empty()) 10946 continue; 10947 sprintf(szData, "%g hPa", atof(tstrarray[0].c_str())); 10948 root["result"][ii]["Data"] = szData; 10949 root["result"][ii]["TypeImg"] = "gauge"; 10950 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10951 if (tstrarray.size() > 1) 10952 { 10953 root["result"][ii]["Barometer"] = atof(tstrarray[0].c_str()); 10954 int forecast = atoi(tstrarray[1].c_str()); 10955 root["result"][ii]["Forecast"] = forecast; 10956 root["result"][ii]["ForecastStr"] = BMP_Forecast_Desc(forecast); 10957 } 10958 } 10959 else if (dSubType == sTypeZWaveClock) 10960 { 10961 std::vector<std::string> tstrarray; 10962 StringSplit(sValue, ";", tstrarray); 10963 int day = 0; 10964 int hour = 0; 10965 int minute = 0; 10966 if (tstrarray.size() == 3) 10967 { 10968 day = atoi(tstrarray[0].c_str()); 10969 hour = atoi(tstrarray[1].c_str()); 10970 minute = atoi(tstrarray[2].c_str()); 10971 } 10972 sprintf(szData, "%s %02d:%02d", ZWave_Clock_Days(day), hour, minute); 10973 root["result"][ii]["DayTime"] = sValue; 10974 root["result"][ii]["Data"] = szData; 10975 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10976 root["result"][ii]["TypeImg"] = "clock"; 10977 } 10978 else if (dSubType == sTypeZWaveThermostatMode) 10979 { 10980 strcpy(szData, ""); 10981 root["result"][ii]["Mode"] = nValue; 10982 root["result"][ii]["TypeImg"] = "mode"; 10983 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 10984 std::string modes = ""; 10985 //Add supported modes 10986 #ifdef WITH_OPENZWAVE 10987 if (pHardware) 10988 { 10989 if (pHardware->HwdType == HTYPE_OpenZWave) 10990 { 10991 COpenZWave *pZWave = reinterpret_cast<COpenZWave*>(pHardware); 10992 unsigned long ID; 10993 std::stringstream s_strid; 10994 s_strid << std::hex << sd[1]; 10995 s_strid >> ID; 10996 std::vector<std::string> vmodes = pZWave->GetSupportedThermostatModes(ID); 10997 int smode = 0; 10998 char szTmp[200]; 10999 for (const auto & itt : vmodes) 11000 { 11001 //Value supported 11002 sprintf(szTmp, "%d;%s;", smode, itt.c_str()); 11003 modes += szTmp; 11004 smode++; 11005 } 11006 11007 if (!vmodes.empty()) 11008 { 11009 if (nValue < (int)vmodes.size()) 11010 { 11011 sprintf(szData, "%s", vmodes[nValue].c_str()); 11012 } 11013 } 11014 } 11015 } 11016 #endif 11017 root["result"][ii]["Data"] = szData; 11018 root["result"][ii]["Modes"] = modes; 11019 } 11020 else if (dSubType == sTypeZWaveThermostatFanMode) 11021 { 11022 sprintf(szData, "%s", ZWave_Thermostat_Fan_Modes[nValue]); 11023 root["result"][ii]["Data"] = szData; 11024 root["result"][ii]["Mode"] = nValue; 11025 root["result"][ii]["TypeImg"] = "mode"; 11026 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 11027 //Add supported modes (add all for now) 11028 bool bAddedSupportedModes = false; 11029 std::string modes = ""; 11030 //Add supported modes 11031 #ifdef WITH_OPENZWAVE 11032 if (pHardware) 11033 { 11034 if (pHardware->HwdType == HTYPE_OpenZWave) 11035 { 11036 COpenZWave *pZWave = reinterpret_cast<COpenZWave*>(pHardware); 11037 unsigned long ID; 11038 std::stringstream s_strid; 11039 s_strid << std::hex << sd[1]; 11040 s_strid >> ID; 11041 modes = pZWave->GetSupportedThermostatFanModes(ID); 11042 bAddedSupportedModes = !modes.empty(); 11043 } 11044 } 11045 #endif 11046 if (!bAddedSupportedModes) 11047 { 11048 int smode = 0; 11049 while (ZWave_Thermostat_Fan_Modes[smode] != NULL) 11050 { 11051 sprintf(szTmp, "%d;%s;", smode, ZWave_Thermostat_Fan_Modes[smode]); 11052 modes += szTmp; 11053 smode++; 11054 } 11055 } 11056 root["result"][ii]["Modes"] = modes; 11057 } 11058 else if (dSubType == sTypeZWaveThermostatOperatingState) 11059 { 11060 strcpy(szData, ""); 11061 root["result"][ii]["State"] = nValue; 11062 root["result"][ii]["TypeImg"] = "Fan"; 11063 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 11064 if (nValue == 1) 11065 { 11066 sprintf(szData, "%s", "Cooling"); 11067 } 11068 else if (nValue == 2) 11069 { 11070 sprintf(szData, "%s", "Heating"); 11071 } 11072 else 11073 { 11074 sprintf(szData, "%s", "Idle"); 11075 } 11076 root["result"][ii]["Data"] = szData; 11077 } 11078 else if (dSubType == sTypeZWaveAlarm) 11079 { 11080 sprintf(szData, "Event: 0x%02X (%d)", nValue, nValue); 11081 root["result"][ii]["Data"] = szData; 11082 root["result"][ii]["TypeImg"] = "Alert"; 11083 root["result"][ii]["Level"] = nValue; 11084 root["result"][ii]["HaveTimeout"] = false; 11085 } 11086 } 11087 else if (dType == pTypeLux) 11088 { 11089 sprintf(szTmp, "%.0f Lux", atof(sValue.c_str())); 11090 root["result"][ii]["Data"] = szTmp; 11091 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 11092 } 11093 else if (dType == pTypeWEIGHT) 11094 { 11095 sprintf(szTmp, "%g %s", m_sql.m_weightscale * atof(sValue.c_str()), m_sql.m_weightsign.c_str()); 11096 root["result"][ii]["Data"] = szTmp; 11097 root["result"][ii]["HaveTimeout"] = false; 11098 root["result"][ii]["SwitchTypeVal"] = (m_sql.m_weightsign=="kg") ? 0 : 1; 11099 } 11100 else if (dType == pTypeUsage) 11101 { 11102 if (dSubType == sTypeElectric) 11103 { 11104 sprintf(szData, "%g Watt", atof(sValue.c_str())); 11105 root["result"][ii]["Data"] = szData; 11106 } 11107 else 11108 { 11109 root["result"][ii]["Data"] = sValue; 11110 } 11111 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 11112 } 11113 else if (dType == pTypeRFXSensor) 11114 { 11115 switch (dSubType) 11116 { 11117 case sTypeRFXSensorAD: 11118 sprintf(szData, "%d mV", atoi(sValue.c_str())); 11119 root["result"][ii]["TypeImg"] = "current"; 11120 break; 11121 case sTypeRFXSensorVolt: 11122 sprintf(szData, "%d mV", atoi(sValue.c_str())); 11123 root["result"][ii]["TypeImg"] = "current"; 11124 break; 11125 } 11126 root["result"][ii]["Data"] = szData; 11127 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 11128 } 11129 else if (dType == pTypeRego6XXValue) 11130 { 11131 switch (dSubType) 11132 { 11133 case sTypeRego6XXStatus: 11134 { 11135 std::string lstatus = "On"; 11136 11137 if (atoi(sValue.c_str()) == 0) 11138 { 11139 lstatus = "Off"; 11140 } 11141 root["result"][ii]["Status"] = lstatus; 11142 root["result"][ii]["HaveDimmer"] = false; 11143 root["result"][ii]["MaxDimLevel"] = 0; 11144 root["result"][ii]["HaveGroupCmd"] = false; 11145 root["result"][ii]["TypeImg"] = "utility"; 11146 root["result"][ii]["SwitchTypeVal"] = STYPE_OnOff; 11147 root["result"][ii]["SwitchType"] = Switch_Type_Desc(STYPE_OnOff); 11148 sprintf(szData, "%d", atoi(sValue.c_str())); 11149 root["result"][ii]["Data"] = szData; 11150 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 11151 root["result"][ii]["StrParam1"] = strParam1; 11152 root["result"][ii]["StrParam2"] = strParam2; 11153 root["result"][ii]["Protected"] = (iProtected != 0); 11154 11155 if (CustomImage < static_cast<int>(m_custom_light_icons.size())) 11156 root["result"][ii]["Image"] = m_custom_light_icons[CustomImage].RootFile; 11157 else 11158 root["result"][ii]["Image"] = "Light"; 11159 11160 uint64_t camIDX = m_mainworker.m_cameras.IsDevSceneInCamera(0, sd[0]); 11161 root["result"][ii]["UsedByCamera"] = (camIDX != 0) ? true : false; 11162 if (camIDX != 0) { 11163 std::stringstream scidx; 11164 scidx << camIDX; 11165 root["result"][ii]["CameraIdx"] = scidx.str(); 11166 } 11167 11168 root["result"][ii]["Level"] = 0; 11169 root["result"][ii]["LevelInt"] = atoi(sValue.c_str()); 11170 } 11171 break; 11172 case sTypeRego6XXCounter: 11173 { 11174 //get value of today 11175 time_t now = mytime(NULL); 11176 struct tm ltime; 11177 localtime_r(&now, <ime); 11178 char szDate[40]; 11179 sprintf(szDate, "%04d-%02d-%02d", ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday); 11180 11181 std::vector<std::vector<std::string> > result2; 11182 strcpy(szTmp, "0"); 11183 result2 = m_sql.safe_query("SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID='%q' AND Date>='%q')", 11184 sd[0].c_str(), szDate); 11185 if (!result2.empty()) 11186 { 11187 std::vector<std::string> sd2 = result2[0]; 11188 11189 unsigned long long total_min = std::strtoull(sd2[0].c_str(), nullptr, 10); 11190 unsigned long long total_max = std::strtoull(sd2[1].c_str(), nullptr, 10); 11191 unsigned long long total_real; 11192 11193 total_real = total_max - total_min; 11194 sprintf(szTmp, "%llu", total_real); 11195 } 11196 root["result"][ii]["SwitchTypeVal"] = MTYPE_COUNTER; 11197 root["result"][ii]["Counter"] = sValue; 11198 root["result"][ii]["CounterToday"] = szTmp; 11199 root["result"][ii]["Data"] = sValue; 11200 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 11201 } 11202 break; 11203 } 11204 } 11205 #ifdef ENABLE_PYTHON 11206 if (pHardware != NULL) 11207 { 11208 if (pHardware->HwdType == HTYPE_PythonPlugin) 11209 { 11210 Plugins::CPlugin *pPlugin = (Plugins::CPlugin*)pHardware; 11211 bHaveTimeout = pPlugin->HasNodeFailed(atoi(sd[2].c_str())); 11212 root["result"][ii]["HaveTimeout"] = bHaveTimeout; 11213 } 11214 } 11215 #endif 11216 root["result"][ii]["Timers"] = (bHasTimers == true) ? "true" : "false"; 11217 ii++; 11218 } 11219 } 11220 } 11221 UploadFloorplanImage(WebEmSession & session,const request & req,std::string & redirect_uri)11222 void CWebServer::UploadFloorplanImage(WebEmSession & session, const request& req, std::string & redirect_uri) 11223 { 11224 redirect_uri = "/index.html"; 11225 if (session.rights != 2) 11226 { 11227 session.reply_status = reply::forbidden; 11228 return; //Only admin user allowed 11229 } 11230 11231 std::string planname = request::findValue(&req, "planname"); 11232 std::string scalefactor = request::findValue(&req, "scalefactor"); 11233 std::string imagefile = request::findValue(&req, "imagefile"); 11234 11235 std::vector<std::vector<std::string> > result; 11236 m_sql.safe_query("INSERT INTO Floorplans ([Name],[ScaleFactor]) VALUES('%s','%s')", planname.c_str(),scalefactor.c_str()); 11237 result = m_sql.safe_query("SELECT MAX(ID) FROM Floorplans"); 11238 if (!result.empty()) 11239 { 11240 if (!m_sql.safe_UpdateBlobInTableWithID("Floorplans", "Image", result[0][0], imagefile)) 11241 _log.Log(LOG_ERROR, "SQL: Problem inserting floorplan image into database! "); 11242 } 11243 } 11244 GetFloorplanImage(WebEmSession & session,const request & req,reply & rep)11245 void CWebServer::GetFloorplanImage(WebEmSession & session, const request& req, reply & rep) 11246 { 11247 std::string idx = request::findValue(&req, "idx"); 11248 if (idx == "") { 11249 return; 11250 } 11251 std::vector<std::vector<std::string> > result; 11252 result = m_sql.safe_queryBlob("SELECT Image FROM Floorplans WHERE ID=%d", atol(idx.c_str())); 11253 if (result.empty()) 11254 return; 11255 reply::set_content(&rep, result[0][0].begin(), result[0][0].end()); 11256 std::string oname = "floorplan"; 11257 if (result[0][0].size() > 10) 11258 { 11259 if (result[0][0][0] == 'P') 11260 oname += ".png"; 11261 else if (result[0][0][0] == -1) 11262 oname += ".jpg"; 11263 else if (result[0][0][0] == 'B') 11264 oname += ".bmp"; 11265 else if (result[0][0][0] == 'G') 11266 oname += ".gif"; 11267 else if ((result[0][0][0] == '<') && (result[0][0][1] == 's') && (result[0][0][2] == 'v') && (result[0][0][3] == 'g')) 11268 oname += ".svg"; 11269 else if (result[0][0].find("<svg") != std::string::npos) //some SVG's start with <xml 11270 oname += ".svg"; 11271 } 11272 reply::add_header_attachment(&rep, oname); 11273 } 11274 GetDatabaseBackup(WebEmSession & session,const request & req,reply & rep)11275 void CWebServer::GetDatabaseBackup(WebEmSession & session, const request& req, reply & rep) 11276 { 11277 if (session.rights != 2) 11278 { 11279 session.reply_status = reply::forbidden; 11280 return; //Only admin user allowed 11281 } 11282 time_t now = mytime(NULL); 11283 Json::Value backupInfo; 11284 11285 backupInfo["type"] = "Web"; 11286 #ifdef WIN32 11287 backupInfo["location"] = szUserDataFolder + "backup.db"; 11288 #else 11289 backupInfo["location"] = "/tmp/backup.db"; 11290 #endif 11291 if (m_sql.BackupDatabase(backupInfo["location"].asString())) 11292 { 11293 std::string szAttachmentName = "domoticz.db"; 11294 std::string szVar; 11295 if (m_sql.GetPreferencesVar("Title", szVar)) 11296 { 11297 stdreplace(szVar, " ", "_"); 11298 stdreplace(szVar, "/", "_"); 11299 stdreplace(szVar, "\\", "_"); 11300 if (!szVar.empty()) { 11301 szAttachmentName = szVar + ".db"; 11302 } 11303 } 11304 reply::set_download_file(&rep, backupInfo["location"].asString(), szAttachmentName); 11305 backupInfo["duration"] = difftime(mytime(NULL),now); 11306 m_mainworker.m_notificationsystem.Notify(Notification::DZ_BACKUP_DONE, Notification::STATUS_INFO, JSonToRawString(backupInfo)); 11307 } 11308 } 11309 RType_DeleteDevice(WebEmSession & session,const request & req,Json::Value & root)11310 void CWebServer::RType_DeleteDevice(WebEmSession & session, const request& req, Json::Value &root) 11311 { 11312 if (session.rights != 2) 11313 { 11314 session.reply_status = reply::forbidden; 11315 return; //Only admin user allowed 11316 } 11317 11318 std::string idx = request::findValue(&req, "idx"); 11319 if (idx.empty()) 11320 return; 11321 11322 root["status"] = "OK"; 11323 root["title"] = "DeleteDevice"; 11324 m_sql.DeleteDevices(idx); 11325 m_mainworker.m_scheduler.ReloadSchedules(); 11326 } 11327 RType_AddScene(WebEmSession & session,const request & req,Json::Value & root)11328 void CWebServer::RType_AddScene(WebEmSession & session, const request& req, Json::Value &root) 11329 { 11330 if (session.rights != 2) 11331 { 11332 session.reply_status = reply::forbidden; 11333 return; //Only admin user allowed 11334 } 11335 11336 std::string name = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 11337 name = HTMLSanitizer::Sanitize(name); 11338 if (name.empty()) 11339 { 11340 root["status"] = "ERR"; 11341 root["message"] = "No Scene Name specified!"; 11342 return; 11343 } 11344 std::string stype = request::findValue(&req, "scenetype"); 11345 if (stype.empty()) 11346 { 11347 root["status"] = "ERR"; 11348 root["message"] = "No Scene Type specified!"; 11349 return; 11350 } 11351 if (m_sql.DoesSceneByNameExits(name) == true) 11352 { 11353 root["status"] = "ERR"; 11354 root["message"] = "A Scene with this Name already Exits!"; 11355 return; 11356 } 11357 root["status"] = "OK"; 11358 root["title"] = "AddScene"; 11359 m_sql.safe_query( 11360 "INSERT INTO Scenes (Name,SceneType) VALUES ('%q',%d)", 11361 name.c_str(), 11362 atoi(stype.c_str()) 11363 ); 11364 if (m_sql.m_bEnableEventSystem) 11365 { 11366 m_mainworker.m_eventsystem.GetCurrentScenesGroups(); 11367 } 11368 } 11369 RType_DeleteScene(WebEmSession & session,const request & req,Json::Value & root)11370 void CWebServer::RType_DeleteScene(WebEmSession & session, const request& req, Json::Value &root) 11371 { 11372 if (session.rights != 2) 11373 { 11374 session.reply_status = reply::forbidden; 11375 return; //Only admin user allowed 11376 } 11377 11378 std::string idx = request::findValue(&req, "idx"); 11379 if (idx.empty()) 11380 return; 11381 root["status"] = "OK"; 11382 root["title"] = "DeleteScene"; 11383 m_sql.DeleteScenes(idx); 11384 } 11385 RType_UpdateScene(WebEmSession & session,const request & req,Json::Value & root)11386 void CWebServer::RType_UpdateScene(WebEmSession & session, const request& req, Json::Value &root) 11387 { 11388 if (session.rights != 2) 11389 { 11390 session.reply_status = reply::forbidden; 11391 return; //Only admin user allowed 11392 } 11393 11394 std::string idx = request::findValue(&req, "idx"); 11395 std::string name = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 11396 std::string description = HTMLSanitizer::Sanitize(request::findValue(&req, "description")); 11397 11398 name = HTMLSanitizer::Sanitize(name); 11399 description = HTMLSanitizer::Sanitize(description); 11400 11401 if ((idx.empty()) || (name.empty())) 11402 return; 11403 std::string stype = request::findValue(&req, "scenetype"); 11404 if (stype.empty()) 11405 { 11406 root["status"] = "ERR"; 11407 root["message"] = "No Scene Type specified!"; 11408 return; 11409 } 11410 std::string tmpstr = request::findValue(&req, "protected"); 11411 int iProtected = (tmpstr == "true") ? 1 : 0; 11412 11413 std::string onaction = base64_decode(request::findValue(&req, "onaction")); 11414 std::string offaction = base64_decode(request::findValue(&req, "offaction")); 11415 11416 11417 root["status"] = "OK"; 11418 root["title"] = "UpdateScene"; 11419 m_sql.safe_query("UPDATE Scenes SET Name='%q', Description='%q', SceneType=%d, Protected=%d, OnAction='%q', OffAction='%q' WHERE (ID == '%q')", 11420 name.c_str(), 11421 description.c_str(), 11422 atoi(stype.c_str()), 11423 iProtected, 11424 onaction.c_str(), 11425 offaction.c_str(), 11426 idx.c_str() 11427 ); 11428 uint64_t ullidx = std::strtoull(idx.c_str(), nullptr, 10); 11429 m_mainworker.m_eventsystem.WWWUpdateSingleState(ullidx, name, m_mainworker.m_eventsystem.REASON_SCENEGROUP); 11430 } 11431 compareIconsByName(const http::server::CWebServer::_tCustomIcon & a,const http::server::CWebServer::_tCustomIcon & b)11432 bool compareIconsByName(const http::server::CWebServer::_tCustomIcon &a, const http::server::CWebServer::_tCustomIcon &b) 11433 { 11434 return a.Title < b.Title; 11435 } 11436 RType_CustomLightIcons(WebEmSession & session,const request & req,Json::Value & root)11437 void CWebServer::RType_CustomLightIcons(WebEmSession & session, const request& req, Json::Value &root) 11438 { 11439 int ii = 0; 11440 11441 std::vector<_tCustomIcon> temp_custom_light_icons = m_custom_light_icons; 11442 //Sort by name 11443 std::sort(temp_custom_light_icons.begin(), temp_custom_light_icons.end(), compareIconsByName); 11444 11445 for (const auto & itt : temp_custom_light_icons) 11446 { 11447 root["result"][ii]["idx"] = itt.idx; 11448 root["result"][ii]["imageSrc"] = itt.RootFile; 11449 root["result"][ii]["text"] = itt.Title; 11450 root["result"][ii]["description"] = itt.Description; 11451 ii++; 11452 } 11453 root["status"] = "OK"; 11454 } 11455 RType_Plans(WebEmSession & session,const request & req,Json::Value & root)11456 void CWebServer::RType_Plans(WebEmSession & session, const request& req, Json::Value &root) 11457 { 11458 root["status"] = "OK"; 11459 root["title"] = "Plans"; 11460 11461 std::string sDisplayHidden = request::findValue(&req, "displayhidden"); 11462 bool bDisplayHidden = (sDisplayHidden == "1"); 11463 11464 std::vector<std::vector<std::string> > result, result2; 11465 result = m_sql.safe_query("SELECT ID, Name, [Order] FROM Plans ORDER BY [Order]"); 11466 if (!result.empty()) 11467 { 11468 int ii = 0; 11469 for (const auto & itt : result) 11470 { 11471 std::vector<std::string> sd = itt; 11472 11473 std::string Name = sd[1]; 11474 bool bIsHidden = (Name[0] == '$'); 11475 11476 if ((bDisplayHidden) || (!bIsHidden)) 11477 { 11478 root["result"][ii]["idx"] = sd[0]; 11479 root["result"][ii]["Name"] = Name; 11480 root["result"][ii]["Order"] = sd[2]; 11481 11482 unsigned int totDevices = 0; 11483 11484 result2 = m_sql.safe_query("SELECT COUNT(*) FROM DeviceToPlansMap WHERE (PlanID=='%q')", 11485 sd[0].c_str()); 11486 if (!result2.empty()) 11487 { 11488 totDevices = (unsigned int)atoi(result2[0][0].c_str()); 11489 } 11490 root["result"][ii]["Devices"] = totDevices; 11491 11492 ii++; 11493 } 11494 } 11495 } 11496 } 11497 RType_FloorPlans(WebEmSession & session,const request & req,Json::Value & root)11498 void CWebServer::RType_FloorPlans(WebEmSession & session, const request& req, Json::Value &root) 11499 { 11500 root["status"] = "OK"; 11501 root["title"] = "Floorplans"; 11502 11503 std::vector<std::vector<std::string> > result, result2, result3; 11504 11505 result = m_sql.safe_query("SELECT Key, nValue, sValue FROM Preferences WHERE Key LIKE 'Floorplan%%'"); 11506 if (result.empty()) 11507 return; 11508 11509 for (const auto & itt : result) 11510 { 11511 std::vector<std::string> sd = itt; 11512 std::string Key = sd[0]; 11513 int nValue = atoi(sd[1].c_str()); 11514 std::string sValue = sd[2]; 11515 11516 if (Key == "FloorplanPopupDelay") 11517 { 11518 root["PopupDelay"] = nValue; 11519 } 11520 if (Key == "FloorplanFullscreenMode") 11521 { 11522 root["FullscreenMode"] = nValue; 11523 } 11524 if (Key == "FloorplanAnimateZoom") 11525 { 11526 root["AnimateZoom"] = nValue; 11527 } 11528 if (Key == "FloorplanShowSensorValues") 11529 { 11530 root["ShowSensorValues"] = nValue; 11531 } 11532 if (Key == "FloorplanShowSwitchValues") 11533 { 11534 root["ShowSwitchValues"] = nValue; 11535 } 11536 if (Key == "FloorplanShowSceneNames") 11537 { 11538 root["ShowSceneNames"] = nValue; 11539 } 11540 if (Key == "FloorplanRoomColour") 11541 { 11542 root["RoomColour"] = sValue; 11543 } 11544 if (Key == "FloorplanActiveOpacity") 11545 { 11546 root["ActiveRoomOpacity"] = nValue; 11547 } 11548 if (Key == "FloorplanInactiveOpacity") 11549 { 11550 root["InactiveRoomOpacity"] = nValue; 11551 } 11552 } 11553 11554 result2 = m_sql.safe_query("SELECT ID, Name, ScaleFactor, [Order] FROM Floorplans ORDER BY [Order]"); 11555 if (!result2.empty()) 11556 { 11557 int ii = 0; 11558 for (const auto & itt : result2) 11559 { 11560 std::vector<std::string> sd = itt; 11561 11562 root["result"][ii]["idx"] = sd[0]; 11563 root["result"][ii]["Name"] = sd[1]; 11564 std::string ImageURL = "images/floorplans/plan?idx=" + sd[0]; 11565 root["result"][ii]["Image"] = ImageURL; 11566 root["result"][ii]["ScaleFactor"] = sd[2]; 11567 root["result"][ii]["Order"] = sd[3]; 11568 11569 unsigned int totPlans = 0; 11570 11571 result3 = m_sql.safe_query("SELECT COUNT(*) FROM Plans WHERE (FloorplanID=='%q')", sd[0].c_str()); 11572 if (!result3.empty()) 11573 { 11574 totPlans = (unsigned int)atoi(result3[0][0].c_str()); 11575 } 11576 root["result"][ii]["Plans"] = totPlans; 11577 11578 ii++; 11579 } 11580 } 11581 } 11582 RType_Scenes(WebEmSession & session,const request & req,Json::Value & root)11583 void CWebServer::RType_Scenes(WebEmSession & session, const request& req, Json::Value &root) 11584 { 11585 root["status"] = "OK"; 11586 root["title"] = "Scenes"; 11587 root["AllowWidgetOrdering"] = m_sql.m_bAllowWidgetOrdering; 11588 11589 std::string sDisplayHidden = request::findValue(&req, "displayhidden"); 11590 bool bDisplayHidden = (sDisplayHidden == "1"); 11591 11592 std::string sLastUpdate = request::findValue(&req, "lastupdate"); 11593 11594 std::string rid = request::findValue(&req, "rid"); 11595 11596 time_t LastUpdate = 0; 11597 if (sLastUpdate != "") 11598 { 11599 std::stringstream sstr; 11600 sstr << sLastUpdate; 11601 sstr >> LastUpdate; 11602 } 11603 11604 time_t now = mytime(NULL); 11605 struct tm tm1; 11606 localtime_r(&now, &tm1); 11607 struct tm tLastUpdate; 11608 localtime_r(&now, &tLastUpdate); 11609 11610 root["ActTime"] = static_cast<int>(now); 11611 11612 std::vector<std::vector<std::string> > result, result2; 11613 std::string szQuery = "SELECT ID, Name, Activators, Favorite, nValue, SceneType, LastUpdate, Protected, OnAction, OffAction, Description FROM Scenes"; 11614 if (!rid.empty()) 11615 szQuery += " WHERE (ID == " + rid + ")"; 11616 szQuery += " ORDER BY [Order]"; 11617 result = m_sql.safe_query(szQuery.c_str()); 11618 if (!result.empty()) 11619 { 11620 int ii = 0; 11621 for (const auto & itt : result) 11622 { 11623 std::vector<std::string> sd = itt; 11624 11625 std::string sName = sd[1]; 11626 if ((bDisplayHidden == false) && (sName[0] == '$')) 11627 continue; 11628 11629 std::string sLastUpdate = sd[6].c_str(); 11630 if (LastUpdate != 0) 11631 { 11632 time_t cLastUpdate; 11633 ParseSQLdatetime(cLastUpdate, tLastUpdate, sLastUpdate, tm1.tm_isdst); 11634 if (cLastUpdate <= LastUpdate) 11635 continue; 11636 } 11637 11638 unsigned char nValue = atoi(sd[4].c_str()); 11639 unsigned char scenetype = atoi(sd[5].c_str()); 11640 int iProtected = atoi(sd[7].c_str()); 11641 11642 std::string onaction = base64_encode(sd[8]); 11643 std::string offaction = base64_encode(sd[9]); 11644 11645 root["result"][ii]["idx"] = sd[0]; 11646 root["result"][ii]["Name"] = sName; 11647 root["result"][ii]["Description"] = sd[10]; 11648 root["result"][ii]["Favorite"] = atoi(sd[3].c_str()); 11649 root["result"][ii]["Protected"] = (iProtected != 0); 11650 root["result"][ii]["OnAction"] = onaction; 11651 root["result"][ii]["OffAction"] = offaction; 11652 11653 if (scenetype == 0) 11654 { 11655 root["result"][ii]["Type"] = "Scene"; 11656 } 11657 else 11658 { 11659 root["result"][ii]["Type"] = "Group"; 11660 } 11661 11662 root["result"][ii]["LastUpdate"] = sLastUpdate; 11663 11664 if (nValue == 0) 11665 root["result"][ii]["Status"] = "Off"; 11666 else if (nValue == 1) 11667 root["result"][ii]["Status"] = "On"; 11668 else 11669 root["result"][ii]["Status"] = "Mixed"; 11670 root["result"][ii]["Timers"] = (m_sql.HasSceneTimers(sd[0]) == true) ? "true" : "false"; 11671 uint64_t camIDX = m_mainworker.m_cameras.IsDevSceneInCamera(1, sd[0]); 11672 root["result"][ii]["UsedByCamera"] = (camIDX != 0) ? true : false; 11673 if (camIDX != 0) { 11674 std::stringstream scidx; 11675 scidx << camIDX; 11676 root["result"][ii]["CameraIdx"] = scidx.str(); 11677 } 11678 ii++; 11679 } 11680 } 11681 if (!m_mainworker.m_LastSunriseSet.empty()) 11682 { 11683 std::vector<std::string> strarray; 11684 StringSplit(m_mainworker.m_LastSunriseSet, ";", strarray); 11685 if (strarray.size() == 10) 11686 { 11687 char szTmp[100]; 11688 //strftime(szTmp, 80, "%b %d %Y %X", &tm1); 11689 strftime(szTmp, 80, "%Y-%m-%d %X", &tm1); 11690 root["ServerTime"] = szTmp; 11691 root["Sunrise"] = strarray[0]; 11692 root["Sunset"] = strarray[1]; 11693 root["SunAtSouth"] = strarray[2]; 11694 root["CivTwilightStart"] = strarray[3]; 11695 root["CivTwilightEnd"] = strarray[4]; 11696 root["NautTwilightStart"] = strarray[5]; 11697 root["NautTwilightEnd"] = strarray[6]; 11698 root["AstrTwilightStart"] = strarray[7]; 11699 root["AstrTwilightEnd"] = strarray[8]; 11700 root["DayLength"] = strarray[9]; 11701 } 11702 } 11703 } 11704 RType_Hardware(WebEmSession & session,const request & req,Json::Value & root)11705 void CWebServer::RType_Hardware(WebEmSession & session, const request& req, Json::Value &root) 11706 { 11707 root["status"] = "OK"; 11708 root["title"] = "Hardware"; 11709 11710 #ifdef WITH_OPENZWAVE 11711 m_ZW_Hwidx = -1; 11712 #endif 11713 11714 std::vector<std::vector<std::string> > result; 11715 result = m_sql.safe_query("SELECT ID, Name, Enabled, Type, Address, Port, SerialPort, Username, Password, Extra, Mode1, Mode2, Mode3, Mode4, Mode5, Mode6, DataTimeout FROM Hardware ORDER BY ID ASC"); 11716 if (!result.empty()) 11717 { 11718 int ii = 0; 11719 for (const auto & itt : result) 11720 { 11721 std::vector<std::string> sd = itt; 11722 11723 _eHardwareTypes hType = (_eHardwareTypes)atoi(sd[3].c_str()); 11724 if (hType == HTYPE_DomoticzInternal) 11725 continue; 11726 root["result"][ii]["idx"] = sd[0]; 11727 root["result"][ii]["Name"] = sd[1]; 11728 root["result"][ii]["Enabled"] = (sd[2] == "1") ? "true" : "false"; 11729 root["result"][ii]["Type"] = hType; 11730 root["result"][ii]["Address"] = sd[4]; 11731 root["result"][ii]["Port"] = atoi(sd[5].c_str()); 11732 root["result"][ii]["SerialPort"] = sd[6]; 11733 root["result"][ii]["Username"] = sd[7]; 11734 root["result"][ii]["Password"] = sd[8]; 11735 root["result"][ii]["Extra"] = sd[9]; 11736 11737 if (hType == HTYPE_PythonPlugin) { 11738 root["result"][ii]["Mode1"] = sd[10]; // Plugins can have non-numeric values in the Mode fields 11739 root["result"][ii]["Mode2"] = sd[11]; 11740 root["result"][ii]["Mode3"] = sd[12]; 11741 root["result"][ii]["Mode4"] = sd[13]; 11742 root["result"][ii]["Mode5"] = sd[14]; 11743 root["result"][ii]["Mode6"] = sd[15]; 11744 } 11745 else { 11746 root["result"][ii]["Mode1"] = atoi(sd[10].c_str()); 11747 root["result"][ii]["Mode2"] = atoi(sd[11].c_str()); 11748 root["result"][ii]["Mode3"] = atoi(sd[12].c_str()); 11749 root["result"][ii]["Mode4"] = atoi(sd[13].c_str()); 11750 root["result"][ii]["Mode5"] = atoi(sd[14].c_str()); 11751 root["result"][ii]["Mode6"] = atoi(sd[15].c_str()); 11752 } 11753 root["result"][ii]["DataTimeout"] = atoi(sd[16].c_str()); 11754 11755 //Special case for openzwave (status for nodes queried) 11756 CDomoticzHardwareBase *pHardware = m_mainworker.GetHardware(atoi(sd[0].c_str())); 11757 if (pHardware != NULL) 11758 { 11759 if ( 11760 (pHardware->HwdType == HTYPE_RFXtrx315) || 11761 (pHardware->HwdType == HTYPE_RFXtrx433) || 11762 (pHardware->HwdType == HTYPE_RFXtrx868) || 11763 (pHardware->HwdType == HTYPE_RFXLAN) 11764 ) 11765 { 11766 CRFXBase *pMyHardware = reinterpret_cast<CRFXBase*>(pHardware); 11767 if (!pMyHardware->m_Version.empty()) 11768 root["result"][ii]["version"] = pMyHardware->m_Version; 11769 else 11770 root["result"][ii]["version"] = sd[11]; 11771 root["result"][ii]["noiselvl"] = pMyHardware->m_NoiseLevel; 11772 } 11773 else if ((pHardware->HwdType == HTYPE_MySensorsUSB) || (pHardware->HwdType == HTYPE_MySensorsTCP) || (pHardware->HwdType == HTYPE_MySensorsMQTT)) 11774 { 11775 MySensorsBase *pMyHardware = reinterpret_cast<MySensorsBase*>(pHardware); 11776 root["result"][ii]["version"] = pMyHardware->GetGatewayVersion(); 11777 } 11778 else if ((pHardware->HwdType == HTYPE_OpenThermGateway) || (pHardware->HwdType == HTYPE_OpenThermGatewayTCP)) 11779 { 11780 OTGWBase *pMyHardware = reinterpret_cast<OTGWBase*>(pHardware); 11781 root["result"][ii]["version"] = pMyHardware->m_Version; 11782 } 11783 else if ((pHardware->HwdType == HTYPE_RFLINKUSB) || (pHardware->HwdType == HTYPE_RFLINKTCP)) 11784 { 11785 CRFLinkBase *pMyHardware = reinterpret_cast<CRFLinkBase*>(pHardware); 11786 root["result"][ii]["version"] = pMyHardware->m_Version; 11787 } 11788 else 11789 { 11790 #ifdef WITH_OPENZWAVE 11791 if (pHardware->HwdType == HTYPE_OpenZWave) 11792 { 11793 COpenZWave *pOZWHardware = reinterpret_cast<COpenZWave*>(pHardware); 11794 root["result"][ii]["version"] = pOZWHardware->GetVersionLong(); 11795 root["result"][ii]["NodesQueried"] = (pOZWHardware->m_awakeNodesQueried || pOZWHardware->m_allNodesQueried); 11796 } 11797 #endif 11798 } 11799 } 11800 ii++; 11801 } 11802 } 11803 } 11804 RType_Devices(WebEmSession & session,const request & req,Json::Value & root)11805 void CWebServer::RType_Devices(WebEmSession & session, const request& req, Json::Value &root) 11806 { 11807 std::string rfilter = request::findValue(&req, "filter"); 11808 std::string order = request::findValue(&req, "order"); 11809 std::string rused = request::findValue(&req, "used"); 11810 std::string rid = request::findValue(&req, "rid"); 11811 std::string planid = request::findValue(&req, "plan"); 11812 std::string floorid = request::findValue(&req, "floor"); 11813 std::string sDisplayHidden = request::findValue(&req, "displayhidden"); 11814 std::string sFetchFavorites = request::findValue(&req, "favorite"); 11815 std::string sDisplayDisabled = request::findValue(&req, "displaydisabled"); 11816 bool bDisplayHidden = (sDisplayHidden == "1"); 11817 bool bFetchFavorites = (sFetchFavorites == "1"); 11818 11819 int HideDisabledHardwareSensors = 0; 11820 m_sql.GetPreferencesVar("HideDisabledHardwareSensors", HideDisabledHardwareSensors); 11821 bool bDisabledDisabled = (HideDisabledHardwareSensors == 0); 11822 if (sDisplayDisabled == "1") 11823 bDisabledDisabled = true; 11824 11825 std::string sLastUpdate = request::findValue(&req, "lastupdate"); 11826 std::string hwidx = request::findValue(&req, "hwidx"); // OTO 11827 11828 time_t LastUpdate = 0; 11829 if (sLastUpdate != "") 11830 { 11831 std::stringstream sstr; 11832 sstr << sLastUpdate; 11833 sstr >> LastUpdate; 11834 } 11835 11836 root["status"] = "OK"; 11837 root["title"] = "Devices"; 11838 root["app_version"] = szAppVersion; 11839 GetJSonDevices(root, rused, rfilter, order, rid, planid, floorid, bDisplayHidden, bDisabledDisabled, bFetchFavorites, LastUpdate, session.username, hwidx); 11840 } 11841 RType_Users(WebEmSession & session,const request & req,Json::Value & root)11842 void CWebServer::RType_Users(WebEmSession & session, const request& req, Json::Value &root) 11843 { 11844 bool bHaveUser = (session.username != ""); 11845 int urights = 3; 11846 if (bHaveUser) 11847 { 11848 int iUser = FindUser(session.username.c_str()); 11849 if (iUser != -1) 11850 urights = static_cast<int>(m_users[iUser].userrights); 11851 } 11852 if (urights < 2) 11853 return; 11854 11855 root["status"] = "OK"; 11856 root["title"] = "Users"; 11857 11858 std::vector<std::vector<std::string> > result; 11859 result = m_sql.safe_query("SELECT ID, Active, Username, Password, Rights, RemoteSharing, TabsEnabled FROM USERS ORDER BY ID ASC"); 11860 if (!result.empty()) 11861 { 11862 int ii = 0; 11863 for (const auto & itt : result) 11864 { 11865 std::vector<std::string> sd = itt; 11866 11867 root["result"][ii]["idx"] = sd[0]; 11868 root["result"][ii]["Enabled"] = (sd[1] == "1") ? "true" : "false"; 11869 root["result"][ii]["Username"] = base64_decode(sd[2]); 11870 root["result"][ii]["Password"] = sd[3]; 11871 root["result"][ii]["Rights"] = atoi(sd[4].c_str()); 11872 root["result"][ii]["RemoteSharing"] = atoi(sd[5].c_str()); 11873 root["result"][ii]["TabsEnabled"] = atoi(sd[6].c_str()); 11874 ii++; 11875 } 11876 } 11877 } 11878 RType_Mobiles(WebEmSession & session,const request & req,Json::Value & root)11879 void CWebServer::RType_Mobiles(WebEmSession & session, const request& req, Json::Value &root) 11880 { 11881 bool bHaveUser = (session.username != ""); 11882 int urights = 3; 11883 if (bHaveUser) 11884 { 11885 int iUser = FindUser(session.username.c_str()); 11886 if (iUser != -1) 11887 urights = static_cast<int>(m_users[iUser].userrights); 11888 } 11889 if (urights < 2) 11890 return; 11891 11892 root["status"] = "OK"; 11893 root["title"] = "Mobiles"; 11894 11895 std::vector<std::vector<std::string> > result; 11896 result = m_sql.safe_query("SELECT ID, Active, Name, UUID, LastUpdate, DeviceType FROM MobileDevices ORDER BY Name ASC"); 11897 if (!result.empty()) 11898 { 11899 int ii = 0; 11900 for (const auto & itt : result) 11901 { 11902 std::vector<std::string> sd = itt; 11903 11904 root["result"][ii]["idx"] = sd[0]; 11905 root["result"][ii]["Enabled"] = (sd[1] == "1") ? "true" : "false"; 11906 root["result"][ii]["Name"] = sd[2]; 11907 root["result"][ii]["UUID"] = sd[3]; 11908 root["result"][ii]["LastUpdate"] = sd[4]; 11909 root["result"][ii]["DeviceType"] = sd[5]; 11910 ii++; 11911 } 11912 } 11913 } 11914 Cmd_SetSetpoint(WebEmSession & session,const request & req,Json::Value & root)11915 void CWebServer::Cmd_SetSetpoint(WebEmSession & session, const request& req, Json::Value &root) 11916 { 11917 bool bHaveUser = (session.username != ""); 11918 int iUser = -1; 11919 int urights = 3; 11920 if (bHaveUser) 11921 { 11922 iUser = FindUser(session.username.c_str()); 11923 if (iUser != -1) 11924 { 11925 urights = static_cast<int>(m_users[iUser].userrights); 11926 } 11927 } 11928 if (urights < 1) 11929 return; 11930 11931 std::string idx = request::findValue(&req, "idx"); 11932 std::string setpoint = request::findValue(&req, "setpoint"); 11933 if ( 11934 (idx.empty()) || 11935 (setpoint.empty()) 11936 ) 11937 return; 11938 root["status"] = "OK"; 11939 root["title"] = "SetSetpoint"; 11940 if (iUser != -1) 11941 { 11942 _log.Log(LOG_STATUS, "User: %s initiated a SetPoint command", m_users[iUser].Username.c_str()); 11943 } 11944 m_mainworker.SetSetPoint(idx, static_cast<float>(atof(setpoint.c_str()))); 11945 } 11946 Cmd_GetSceneActivations(WebEmSession & session,const request & req,Json::Value & root)11947 void CWebServer::Cmd_GetSceneActivations(WebEmSession & session, const request& req, Json::Value &root) 11948 { 11949 if (session.rights != 2) 11950 { 11951 session.reply_status = reply::forbidden; 11952 return; //Only admin user allowed 11953 } 11954 11955 std::string idx = request::findValue(&req, "idx"); 11956 if (idx.empty()) 11957 return; 11958 11959 root["status"] = "OK"; 11960 root["title"] = "GetSceneActivations"; 11961 11962 std::vector<std::vector<std::string> > result, result2; 11963 result = m_sql.safe_query("SELECT Activators, SceneType FROM Scenes WHERE (ID==%q)", idx.c_str()); 11964 if (result.empty()) 11965 return; 11966 int ii = 0; 11967 std::string Activators = result[0][0]; 11968 int SceneType = atoi(result[0][1].c_str()); 11969 if (!Activators.empty()) 11970 { 11971 //Get Activator device names 11972 std::vector<std::string> arrayActivators; 11973 StringSplit(Activators, ";", arrayActivators); 11974 for (const auto & ittAct : arrayActivators) 11975 { 11976 std::string sCodeCmd = ittAct; 11977 11978 std::vector<std::string> arrayCode; 11979 StringSplit(sCodeCmd, ":", arrayCode); 11980 11981 std::string sID = arrayCode[0]; 11982 int sCode = 0; 11983 if (arrayCode.size() == 2) 11984 { 11985 sCode = atoi(arrayCode[1].c_str()); 11986 } 11987 11988 11989 result2 = m_sql.safe_query("SELECT Name, [Type], SubType, SwitchType FROM DeviceStatus WHERE (ID==%q)", sID.c_str()); 11990 if (!result2.empty()) 11991 { 11992 std::vector<std::string> sd = result2[0]; 11993 std::string lstatus = "-"; 11994 if ((SceneType == 0) && (arrayCode.size() == 2)) 11995 { 11996 unsigned char devType = (unsigned char)atoi(sd[1].c_str()); 11997 unsigned char subType = (unsigned char)atoi(sd[2].c_str()); 11998 _eSwitchType switchtype = (_eSwitchType)atoi(sd[3].c_str()); 11999 int nValue = sCode; 12000 std::string sValue = ""; 12001 int llevel = 0; 12002 bool bHaveDimmer = false; 12003 bool bHaveGroupCmd = false; 12004 int maxDimLevel = 0; 12005 GetLightStatus(devType, subType, switchtype, nValue, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd); 12006 } 12007 uint64_t dID = std::strtoull(sID.c_str(), nullptr, 10); 12008 root["result"][ii]["idx"] = dID; 12009 root["result"][ii]["name"] = sd[0]; 12010 root["result"][ii]["code"] = sCode; 12011 root["result"][ii]["codestr"] = lstatus; 12012 ii++; 12013 } 12014 } 12015 } 12016 } 12017 Cmd_AddSceneCode(WebEmSession & session,const request & req,Json::Value & root)12018 void CWebServer::Cmd_AddSceneCode(WebEmSession & session, const request& req, Json::Value &root) 12019 { 12020 if (session.rights != 2) 12021 { 12022 session.reply_status = reply::forbidden; 12023 return; //Only admin user allowed 12024 } 12025 12026 std::string sceneidx = request::findValue(&req, "sceneidx"); 12027 std::string idx = request::findValue(&req, "idx"); 12028 std::string cmnd = request::findValue(&req, "cmnd"); 12029 if ( 12030 (sceneidx.empty()) || 12031 (idx.empty()) || 12032 (cmnd.empty()) 12033 ) 12034 return; 12035 root["status"] = "OK"; 12036 root["title"] = "AddSceneCode"; 12037 12038 //First check if we do not already have this device as activation code 12039 std::vector<std::vector<std::string> > result; 12040 result = m_sql.safe_query("SELECT Activators, SceneType FROM Scenes WHERE (ID==%q)", sceneidx.c_str()); 12041 if (result.empty()) 12042 return; 12043 std::string Activators = result[0][0]; 12044 unsigned char scenetype = atoi(result[0][1].c_str()); 12045 12046 if (!Activators.empty()) 12047 { 12048 //Get Activator device names 12049 std::vector<std::string> arrayActivators; 12050 StringSplit(Activators, ";", arrayActivators); 12051 for (const auto & ittAct : arrayActivators) 12052 { 12053 std::string sCodeCmd = ittAct; 12054 12055 std::vector<std::string> arrayCode; 12056 StringSplit(sCodeCmd, ":", arrayCode); 12057 12058 std::string sID = arrayCode[0]; 12059 std::string sCode = ""; 12060 if (arrayCode.size() == 2) 12061 { 12062 sCode = arrayCode[1]; 12063 } 12064 12065 if (sID == idx) 12066 { 12067 if (scenetype == 1) 12068 return; //Group does not work with separate codes, so already there 12069 if (sCode == cmnd) 12070 return; //same code, already there! 12071 } 12072 } 12073 } 12074 if (!Activators.empty()) 12075 Activators += ";"; 12076 Activators += idx; 12077 if (scenetype == 0) 12078 { 12079 Activators += ":" + cmnd; 12080 } 12081 m_sql.safe_query("UPDATE Scenes SET Activators='%q' WHERE (ID==%q)", Activators.c_str(), sceneidx.c_str()); 12082 } 12083 Cmd_RemoveSceneCode(WebEmSession & session,const request & req,Json::Value & root)12084 void CWebServer::Cmd_RemoveSceneCode(WebEmSession & session, const request& req, Json::Value &root) 12085 { 12086 if (session.rights != 2) 12087 { 12088 session.reply_status = reply::forbidden; 12089 return; //Only admin user allowed 12090 } 12091 12092 std::string sceneidx = request::findValue(&req, "sceneidx"); 12093 std::string idx = request::findValue(&req, "idx"); 12094 std::string code = request::findValue(&req, "code"); 12095 if ( 12096 (idx.empty()) || 12097 (sceneidx.empty()) || 12098 (code.empty()) 12099 ) 12100 return; 12101 root["status"] = "OK"; 12102 root["title"] = "RemoveSceneCode"; 12103 12104 std::vector<std::vector<std::string> > result; 12105 result = m_sql.safe_query("SELECT Activators, SceneType FROM Scenes WHERE (ID==%q)", sceneidx.c_str()); 12106 if (result.empty()) 12107 return; 12108 std::string Activators = result[0][0]; 12109 int SceneType = atoi(result[0][1].c_str()); 12110 if (!Activators.empty()) 12111 { 12112 //Get Activator device names 12113 std::vector<std::string> arrayActivators; 12114 StringSplit(Activators, ";", arrayActivators); 12115 std::string newActivation = ""; 12116 for (const auto & ittAct : arrayActivators) 12117 { 12118 std::string sCodeCmd = ittAct; 12119 12120 std::vector<std::string> arrayCode; 12121 StringSplit(sCodeCmd, ":", arrayCode); 12122 12123 std::string sID = arrayCode[0]; 12124 std::string sCode = ""; 12125 if (arrayCode.size() == 2) 12126 { 12127 sCode = arrayCode[1]; 12128 } 12129 bool bFound = false; 12130 if (sID == idx) 12131 { 12132 if ((SceneType == 1) || (sCode.empty())) 12133 { 12134 bFound = true; 12135 } 12136 else 12137 { 12138 //Also check the code 12139 bFound = (sCode == code); 12140 } 12141 } 12142 if (!bFound) 12143 { 12144 if (!newActivation.empty()) 12145 newActivation += ";"; 12146 newActivation += sID; 12147 if ((SceneType == 0) && (!sCode.empty())) 12148 { 12149 newActivation += ":" + sCode; 12150 } 12151 } 12152 } 12153 if (Activators != newActivation) 12154 { 12155 m_sql.safe_query("UPDATE Scenes SET Activators='%q' WHERE (ID==%q)", newActivation.c_str(), sceneidx.c_str()); 12156 } 12157 } 12158 } 12159 Cmd_ClearSceneCodes(WebEmSession & session,const request & req,Json::Value & root)12160 void CWebServer::Cmd_ClearSceneCodes(WebEmSession & session, const request& req, Json::Value &root) 12161 { 12162 if (session.rights != 2) 12163 { 12164 session.reply_status = reply::forbidden; 12165 return; //Only admin user allowed 12166 } 12167 12168 std::string sceneidx = request::findValue(&req, "sceneidx"); 12169 if (sceneidx.empty()) 12170 return; 12171 root["status"] = "OK"; 12172 root["title"] = "ClearSceneCode"; 12173 12174 m_sql.safe_query("UPDATE Scenes SET Activators='' WHERE (ID==%q)", sceneidx.c_str()); 12175 } 12176 Cmd_GetSerialDevices(WebEmSession & session,const request & req,Json::Value & root)12177 void CWebServer::Cmd_GetSerialDevices(WebEmSession & session, const request& req, Json::Value &root) 12178 { 12179 root["status"] = "OK"; 12180 root["title"] = "GetSerialDevices"; 12181 12182 bool bUseDirectPath = false; 12183 std::vector<std::string> serialports = GetSerialPorts(bUseDirectPath); 12184 int ii = 0; 12185 for (const auto & itt : serialports) 12186 { 12187 root["result"][ii]["name"] = itt; 12188 root["result"][ii]["value"] = ii; 12189 ii++; 12190 } 12191 } 12192 Cmd_GetDevicesList(WebEmSession & session,const request & req,Json::Value & root)12193 void CWebServer::Cmd_GetDevicesList(WebEmSession & session, const request& req, Json::Value &root) 12194 { 12195 root["status"] = "OK"; 12196 root["title"] = "GetDevicesList"; 12197 int ii = 0; 12198 std::vector<std::vector<std::string> > result; 12199 result = m_sql.safe_query("SELECT ID, Name FROM DeviceStatus WHERE (Used == 1) ORDER BY Name"); 12200 if (!result.empty()) 12201 { 12202 for (const auto & itt : result) 12203 { 12204 std::vector<std::string> sd = itt; 12205 root["result"][ii]["name"] = sd[1]; 12206 root["result"][ii]["value"] = sd[0]; 12207 ii++; 12208 } 12209 } 12210 } 12211 Post_UploadCustomIcon(WebEmSession & session,const request & req,reply & rep)12212 void CWebServer::Post_UploadCustomIcon(WebEmSession & session, const request& req, reply & rep) 12213 { 12214 Json::Value root; 12215 root["title"] = "UploadCustomIcon"; 12216 root["status"] = "ERROR"; 12217 root["error"] = "Invalid"; 12218 //Only admin user allowed 12219 if (session.rights != 2) 12220 { 12221 session.reply_status = reply::forbidden; 12222 return; //Only admin user allowed 12223 } 12224 std::string zipfile = request::findValue(&req, "file"); 12225 if (zipfile != "") 12226 { 12227 std::string ErrorMessage; 12228 bool bOK = m_sql.InsertCustomIconFromZip(zipfile, ErrorMessage); 12229 if (bOK) 12230 { 12231 root["status"] = "OK"; 12232 } 12233 else 12234 { 12235 root["status"] = "ERROR"; 12236 root["error"] = ErrorMessage; 12237 } 12238 } 12239 std::string jcallback = request::findValue(&req, "jsoncallback"); 12240 if (jcallback.size() == 0) { 12241 reply::set_content(&rep, root.toStyledString()); 12242 return; 12243 } 12244 reply::set_content(&rep, "var data=" + root.toStyledString() + '\n' + jcallback + "(data);"); 12245 } 12246 Cmd_GetCustomIconSet(WebEmSession & session,const request & req,Json::Value & root)12247 void CWebServer::Cmd_GetCustomIconSet(WebEmSession & session, const request& req, Json::Value &root) 12248 { 12249 root["status"] = "OK"; 12250 root["title"] = "GetCustomIconSet"; 12251 int ii = 0; 12252 for (const auto & itt : m_custom_light_icons) 12253 { 12254 if (itt.idx >= 100) 12255 { 12256 std::string IconFile16 = "images/" + itt.RootFile + ".png"; 12257 std::string IconFile48On = "images/" + itt.RootFile + "48_On.png"; 12258 std::string IconFile48Off = "images/" + itt.RootFile + "48_Off.png"; 12259 12260 root["result"][ii]["idx"] = itt.idx - 100; 12261 root["result"][ii]["Title"] = itt.Title; 12262 root["result"][ii]["Description"] = itt.Description; 12263 root["result"][ii]["IconFile16"] = IconFile16; 12264 root["result"][ii]["IconFile48On"] = IconFile48On; 12265 root["result"][ii]["IconFile48Off"] = IconFile48Off; 12266 ii++; 12267 } 12268 } 12269 } 12270 Cmd_DeleteCustomIcon(WebEmSession & session,const request & req,Json::Value & root)12271 void CWebServer::Cmd_DeleteCustomIcon(WebEmSession & session, const request& req, Json::Value &root) 12272 { 12273 if (session.rights != 2) 12274 { 12275 session.reply_status = reply::forbidden; 12276 return; //Only admin user allowed 12277 } 12278 12279 std::string sidx = request::findValue(&req, "idx"); 12280 if (sidx.empty()) 12281 return; 12282 int idx = atoi(sidx.c_str()); 12283 root["status"] = "OK"; 12284 root["title"] = "DeleteCustomIcon"; 12285 12286 m_sql.safe_query("DELETE FROM CustomImages WHERE (ID == %d)", idx); 12287 12288 //Delete icons file from disk 12289 for (const auto & itt : m_custom_light_icons) 12290 { 12291 if (itt.idx == idx + 100) 12292 { 12293 std::string IconFile16 = szWWWFolder + "/images/" + itt.RootFile + ".png"; 12294 std::string IconFile48On = szWWWFolder + "/images/" + itt.RootFile + "48_On.png"; 12295 std::string IconFile48Off = szWWWFolder + "/images/" + itt.RootFile + "48_Off.png"; 12296 std::remove(IconFile16.c_str()); 12297 std::remove(IconFile48On.c_str()); 12298 std::remove(IconFile48Off.c_str()); 12299 break; 12300 } 12301 } 12302 ReloadCustomSwitchIcons(); 12303 } 12304 Cmd_UpdateCustomIcon(WebEmSession & session,const request & req,Json::Value & root)12305 void CWebServer::Cmd_UpdateCustomIcon(WebEmSession & session, const request& req, Json::Value &root) 12306 { 12307 if (session.rights != 2) 12308 { 12309 session.reply_status = reply::forbidden; 12310 return; //Only admin user allowed 12311 } 12312 12313 std::string sidx = request::findValue(&req, "idx"); 12314 std::string sname = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 12315 std::string sdescription = HTMLSanitizer::Sanitize(request::findValue(&req, "description")); 12316 if ( 12317 (sidx.empty()) || 12318 (sname.empty()) || 12319 (sdescription.empty()) 12320 ) 12321 return; 12322 12323 int idx = atoi(sidx.c_str()); 12324 root["status"] = "OK"; 12325 root["title"] = "UpdateCustomIcon"; 12326 12327 m_sql.safe_query("UPDATE CustomImages SET Name='%q', Description='%q' WHERE (ID == %d)", sname.c_str(), sdescription.c_str(), idx); 12328 ReloadCustomSwitchIcons(); 12329 } 12330 Cmd_RenameDevice(WebEmSession & session,const request & req,Json::Value & root)12331 void CWebServer::Cmd_RenameDevice(WebEmSession & session, const request& req, Json::Value &root) 12332 { 12333 if (session.rights != 2) 12334 { 12335 session.reply_status = reply::forbidden; 12336 return; //Only admin user allowed 12337 } 12338 12339 std::string sidx = request::findValue(&req, "idx"); 12340 std::string sname = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 12341 if ( 12342 (sidx.empty()) || 12343 (sname.empty()) 12344 ) 12345 return; 12346 int idx = atoi(sidx.c_str()); 12347 root["status"] = "OK"; 12348 root["title"] = "RenameDevice"; 12349 12350 m_sql.safe_query("UPDATE DeviceStatus SET Name='%q' WHERE (ID == %d)", sname.c_str(), idx); 12351 uint64_t ullidx = std::strtoull(sidx.c_str(), nullptr, 10); 12352 m_mainworker.m_eventsystem.WWWUpdateSingleState(ullidx, sname, m_mainworker.m_eventsystem.REASON_DEVICE); 12353 12354 #ifdef ENABLE_PYTHON 12355 // Notify plugin framework about the change 12356 m_mainworker.m_pluginsystem.DeviceModified(idx); 12357 #endif 12358 } 12359 Cmd_RenameScene(WebEmSession & session,const request & req,Json::Value & root)12360 void CWebServer::Cmd_RenameScene(WebEmSession & session, const request& req, Json::Value &root) 12361 { 12362 if (session.rights != 2) 12363 { 12364 session.reply_status = reply::forbidden; 12365 return; //Only admin user allowed 12366 } 12367 12368 std::string sidx = request::findValue(&req, "idx"); 12369 std::string sname = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 12370 if ( 12371 (sidx.empty()) || 12372 (sname.empty()) 12373 ) 12374 return; 12375 int idx = atoi(sidx.c_str()); 12376 root["status"] = "OK"; 12377 root["title"] = "RenameScene"; 12378 12379 m_sql.safe_query("UPDATE Scenes SET Name='%q' WHERE (ID == %d)", sname.c_str(), idx); 12380 uint64_t ullidx = std::strtoull(sidx.c_str(), nullptr, 10); 12381 m_mainworker.m_eventsystem.WWWUpdateSingleState(ullidx, sname, m_mainworker.m_eventsystem.REASON_SCENEGROUP); 12382 } 12383 Cmd_SetUnused(WebEmSession & session,const request & req,Json::Value & root)12384 void CWebServer::Cmd_SetUnused(WebEmSession & session, const request& req, Json::Value &root) 12385 { 12386 if (session.rights != 2) 12387 { 12388 session.reply_status = reply::forbidden; 12389 return; //Only admin user allowed 12390 } 12391 12392 std::string sidx = request::findValue(&req, "idx"); 12393 if (sidx.empty()) 12394 return; 12395 int idx = atoi(sidx.c_str()); 12396 root["status"] = "OK"; 12397 root["title"] = "SetUnused"; 12398 m_sql.safe_query("UPDATE DeviceStatus SET Used=0 WHERE (ID == %d)", idx); 12399 if (m_sql.m_bEnableEventSystem) 12400 m_mainworker.m_eventsystem.RemoveSingleState(idx, m_mainworker.m_eventsystem.REASON_DEVICE); 12401 12402 #ifdef ENABLE_PYTHON 12403 // Notify plugin framework about the change 12404 m_mainworker.m_pluginsystem.DeviceModified(idx); 12405 #endif 12406 } 12407 Cmd_AddLogMessage(WebEmSession & session,const request & req,Json::Value & root)12408 void CWebServer::Cmd_AddLogMessage(WebEmSession & session, const request& req, Json::Value &root) 12409 { 12410 std::string smessage = request::findValue(&req, "message"); 12411 if (smessage.empty()) 12412 return; 12413 root["status"] = "OK"; 12414 root["title"] = "AddLogMessage"; 12415 12416 _log.Log(LOG_STATUS, "%s", smessage.c_str()); 12417 } 12418 Cmd_ClearShortLog(WebEmSession & session,const request & req,Json::Value & root)12419 void CWebServer::Cmd_ClearShortLog(WebEmSession & session, const request& req, Json::Value &root) 12420 { 12421 if (session.rights != 2) 12422 { 12423 session.reply_status = reply::forbidden; 12424 return; //Only admin user allowed 12425 } 12426 root["status"] = "OK"; 12427 root["title"] = "ClearShortLog"; 12428 12429 _log.Log(LOG_STATUS, "Clearing Short Log..."); 12430 12431 m_sql.ClearShortLog(); 12432 12433 _log.Log(LOG_STATUS, "Short Log Cleared!"); 12434 } 12435 Cmd_VacuumDatabase(WebEmSession & session,const request & req,Json::Value & root)12436 void CWebServer::Cmd_VacuumDatabase(WebEmSession & session, const request& req, Json::Value &root) 12437 { 12438 if (session.rights != 2) 12439 { 12440 session.reply_status = reply::forbidden; 12441 return; //Only admin user allowed 12442 } 12443 root["status"] = "OK"; 12444 root["title"] = "VacuumDatabase"; 12445 12446 m_sql.VacuumDatabase(); 12447 } 12448 Cmd_AddMobileDevice(WebEmSession & session,const request & req,Json::Value & root)12449 void CWebServer::Cmd_AddMobileDevice(WebEmSession & session, const request& req, Json::Value &root) 12450 { 12451 std::string suuid = HTMLSanitizer::Sanitize(request::findValue(&req, "uuid")); 12452 std::string ssenderid = HTMLSanitizer::Sanitize(request::findValue(&req, "senderid")); 12453 std::string sname = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 12454 std::string sdevtype = HTMLSanitizer::Sanitize(request::findValue(&req, "devicetype")); 12455 std::string sactive = request::findValue(&req, "active"); 12456 if ( 12457 (suuid.empty()) || 12458 (ssenderid.empty()) 12459 ) 12460 return; 12461 root["status"] = "OK"; 12462 root["title"] = "AddMobileDevice"; 12463 12464 if (sactive.empty()) 12465 sactive = "1"; 12466 int iActive = (sactive == "1") ? 1 : 0; 12467 12468 std::vector<std::vector<std::string> > result; 12469 result = m_sql.safe_query("SELECT ID, Name, DeviceType FROM MobileDevices WHERE (UUID=='%q')", suuid.c_str()); 12470 if (result.empty()) 12471 { 12472 //New 12473 m_sql.safe_query("INSERT INTO MobileDevices (Active,UUID,SenderID,Name,DeviceType) VALUES (%d,'%q','%q','%q','%q')", 12474 iActive, 12475 suuid.c_str(), 12476 ssenderid.c_str(), 12477 sname.c_str(), 12478 sdevtype.c_str()); 12479 } 12480 else 12481 { 12482 //Update 12483 time_t now = mytime(NULL); 12484 struct tm ltime; 12485 localtime_r(&now, <ime); 12486 m_sql.safe_query("UPDATE MobileDevices SET Active=%d, SenderID='%q', LastUpdate='%04d-%02d-%02d %02d:%02d:%02d' WHERE (UUID == '%q')", 12487 iActive, 12488 ssenderid.c_str(), 12489 ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday, ltime.tm_hour, ltime.tm_min, ltime.tm_sec, 12490 suuid.c_str() 12491 ); 12492 12493 std::string dname = result[0][1]; 12494 std::string ddevtype = result[0][2]; 12495 if (dname.empty() || ddevtype.empty()) 12496 { 12497 m_sql.safe_query("UPDATE MobileDevices SET Name='%q', DeviceType='%q' WHERE (UUID == '%q')", 12498 sname.c_str(), sdevtype.c_str(), 12499 suuid.c_str() 12500 ); 12501 } 12502 } 12503 } 12504 Cmd_UpdateMobileDevice(WebEmSession & session,const request & req,Json::Value & root)12505 void CWebServer::Cmd_UpdateMobileDevice(WebEmSession & session, const request& req, Json::Value &root) 12506 { 12507 if (session.rights != 2) 12508 { 12509 session.reply_status = reply::forbidden; 12510 return; //Only admin user allowed 12511 } 12512 std::string sidx = request::findValue(&req, "idx"); 12513 std::string enabled = request::findValue(&req, "enabled"); 12514 std::string name = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 12515 12516 if ( 12517 (sidx.empty()) || 12518 (enabled.empty()) || 12519 (name.empty()) 12520 ) 12521 return; 12522 uint64_t idx = std::strtoull(sidx.c_str(), nullptr, 10); 12523 12524 m_sql.safe_query("UPDATE MobileDevices SET Name='%q', Active=%d WHERE (ID==%" PRIu64 ")", 12525 name.c_str(), (enabled == "true") ? 1 : 0, idx); 12526 12527 root["status"] = "OK"; 12528 root["title"] = "UpdateMobile"; 12529 } 12530 Cmd_DeleteMobileDevice(WebEmSession & session,const request & req,Json::Value & root)12531 void CWebServer::Cmd_DeleteMobileDevice(WebEmSession & session, const request& req, Json::Value &root) 12532 { 12533 if (session.rights != 2) 12534 { 12535 session.reply_status = reply::forbidden; 12536 return; //Only admin user allowed 12537 } 12538 std::string suuid = request::findValue(&req, "uuid"); 12539 if (suuid.empty()) 12540 return; 12541 std::vector<std::vector<std::string> > result; 12542 result = m_sql.safe_query("SELECT ID FROM MobileDevices WHERE (UUID=='%q')", suuid.c_str()); 12543 if (result.empty()) 12544 return; 12545 m_sql.safe_query("DELETE FROM MobileDevices WHERE (UUID == '%q')", suuid.c_str()); 12546 root["status"] = "OK"; 12547 root["title"] = "DeleteMobileDevice"; 12548 } 12549 12550 RType_GetTransfers(WebEmSession & session,const request & req,Json::Value & root)12551 void CWebServer::RType_GetTransfers(WebEmSession & session, const request& req, Json::Value &root) 12552 { 12553 root["status"] = "OK"; 12554 root["title"] = "GetTransfers"; 12555 12556 uint64_t idx = 0; 12557 if (request::findValue(&req, "idx") != "") 12558 { 12559 idx = std::strtoull(request::findValue(&req, "idx").c_str(), nullptr, 10); 12560 } 12561 12562 std::vector<std::vector<std::string> > result; 12563 result = m_sql.safe_query("SELECT Type, SubType FROM DeviceStatus WHERE (ID==%" PRIu64 ")", 12564 idx); 12565 if (!result.empty()) 12566 { 12567 int dType = atoi(result[0][0].c_str()); 12568 if ( 12569 (dType == pTypeTEMP) 12570 || (dType == pTypeTEMP_HUM) 12571 || (dType == pTypeTEMP_HUM_BARO) 12572 ) 12573 { 12574 result = m_sql.safe_query( 12575 "SELECT ID, Name FROM DeviceStatus WHERE (Type=='%q') AND (ID!=%" PRIu64 ")", 12576 result[0][0].c_str(), idx); 12577 } 12578 else 12579 { 12580 result = m_sql.safe_query( 12581 "SELECT ID, Name FROM DeviceStatus WHERE (Type=='%q') AND (SubType=='%q') AND (ID!=%" PRIu64 ")", 12582 result[0][0].c_str(), result[0][1].c_str(), idx); 12583 } 12584 12585 std::sort(std::begin(result), std::end(result), [](std::vector<std::string> a, std::vector<std::string> b) {return a[1] < b[1]; }); 12586 12587 int ii = 0; 12588 for (const auto & itt : result) 12589 { 12590 std::vector<std::string> sd = itt; 12591 12592 root["result"][ii]["idx"] = sd[0]; 12593 root["result"][ii]["Name"] = sd[1]; 12594 ii++; 12595 } 12596 } 12597 } 12598 12599 //Will transfer Newest sensor log to OLD sensor, 12600 //then set the HardwareID/DeviceID/Unit/Name/Type/Subtype/Unit for the OLD sensor to the NEW sensor ID/Type/Subtype/Unit 12601 //then delete the NEW sensor RType_TransferDevice(WebEmSession & session,const request & req,Json::Value & root)12602 void CWebServer::RType_TransferDevice(WebEmSession & session, const request& req, Json::Value &root) 12603 { 12604 std::string sidx = request::findValue(&req, "idx"); 12605 if (sidx.empty()) 12606 return; 12607 12608 std::string newidx = request::findValue(&req, "newidx"); 12609 if (newidx.empty()) 12610 return; 12611 12612 std::vector<std::vector<std::string> > result; 12613 12614 //Check which device is newer 12615 12616 time_t now = mytime(NULL); 12617 struct tm tm1; 12618 localtime_r(&now, &tm1); 12619 struct tm LastUpdateTime_A; 12620 struct tm LastUpdateTime_B; 12621 12622 result = m_sql.safe_query( 12623 "SELECT A.LastUpdate, B.LastUpdate FROM DeviceStatus as A, DeviceStatus as B WHERE (A.ID == '%q') AND (B.ID == '%q')", 12624 sidx.c_str(), newidx.c_str()); 12625 if (result.empty()) 12626 return; 12627 12628 std::string sLastUpdate_A = result[0][0]; 12629 std::string sLastUpdate_B = result[0][1]; 12630 12631 time_t timeA, timeB; 12632 ParseSQLdatetime(timeA, LastUpdateTime_A, sLastUpdate_A, tm1.tm_isdst); 12633 ParseSQLdatetime(timeB, LastUpdateTime_B, sLastUpdate_B, tm1.tm_isdst); 12634 12635 if (timeA < timeB) 12636 { 12637 //Swap idx with newidx 12638 sidx.swap(newidx); 12639 } 12640 12641 result = m_sql.safe_query( 12642 "SELECT HardwareID, DeviceID, Unit, Name, Type, SubType, SignalLevel, BatteryLevel, nValue, sValue FROM DeviceStatus WHERE (ID == '%q')", 12643 newidx.c_str()); 12644 if (result.empty()) 12645 return; 12646 12647 root["status"] = "OK"; 12648 root["title"] = "TransferDevice"; 12649 12650 //transfer device logs (new to old) 12651 m_sql.TransferDevice(newidx, sidx); 12652 12653 //now delete the NEW device 12654 m_sql.DeleteDevices(newidx); 12655 12656 m_mainworker.m_scheduler.ReloadSchedules(); 12657 } 12658 RType_Notifications(WebEmSession & session,const request & req,Json::Value & root)12659 void CWebServer::RType_Notifications(WebEmSession & session, const request& req, Json::Value &root) 12660 { 12661 root["status"] = "OK"; 12662 root["title"] = "Notifications"; 12663 12664 int ii = 0; 12665 12666 //Add known notification systems 12667 for (const auto & ittNotifiers : m_notifications.m_notifiers) 12668 { 12669 root["notifiers"][ii]["name"] = ittNotifiers.first; 12670 root["notifiers"][ii]["description"] = ittNotifiers.first; 12671 ii++; 12672 } 12673 12674 uint64_t idx = 0; 12675 if (request::findValue(&req, "idx") != "") 12676 { 12677 idx = std::strtoull(request::findValue(&req, "idx").c_str(), nullptr, 10); 12678 } 12679 std::vector<_tNotification> notifications = m_notifications.GetNotifications(idx); 12680 if (notifications.size() > 0) 12681 { 12682 ii = 0; 12683 for (const auto & itt : notifications) 12684 { 12685 root["result"][ii]["idx"] = itt.ID; 12686 std::string sParams = itt.Params; 12687 if (sParams.empty()) { 12688 sParams = "S"; 12689 } 12690 root["result"][ii]["Params"] = sParams; 12691 root["result"][ii]["Priority"] = itt.Priority; 12692 root["result"][ii]["SendAlways"] = itt.SendAlways; 12693 root["result"][ii]["CustomMessage"] = itt.CustomMessage; 12694 root["result"][ii]["ActiveSystems"] = itt.ActiveSystems; 12695 ii++; 12696 } 12697 } 12698 } 12699 RType_GetSharedUserDevices(WebEmSession & session,const request & req,Json::Value & root)12700 void CWebServer::RType_GetSharedUserDevices(WebEmSession & session, const request& req, Json::Value &root) 12701 { 12702 std::string idx = request::findValue(&req, "idx"); 12703 if (idx.empty()) 12704 return; 12705 root["status"] = "OK"; 12706 root["title"] = "GetSharedUserDevices"; 12707 12708 std::vector<std::vector<std::string> > result; 12709 result = m_sql.safe_query("SELECT DeviceRowID FROM SharedDevices WHERE (SharedUserID == '%q')", idx.c_str()); 12710 if (!result.empty()) 12711 { 12712 int ii = 0; 12713 for (const auto & itt : result) 12714 { 12715 std::vector<std::string> sd = itt; 12716 root["result"][ii]["DeviceRowIdx"] = sd[0]; 12717 ii++; 12718 } 12719 } 12720 } 12721 RType_SetSharedUserDevices(WebEmSession & session,const request & req,Json::Value & root)12722 void CWebServer::RType_SetSharedUserDevices(WebEmSession & session, const request& req, Json::Value &root) 12723 { 12724 std::string idx = request::findValue(&req, "idx"); 12725 std::string userdevices = request::findValue(&req, "devices"); 12726 if (idx.empty()) 12727 return; 12728 root["status"] = "OK"; 12729 root["title"] = "SetSharedUserDevices"; 12730 std::vector<std::string> strarray; 12731 StringSplit(userdevices, ";", strarray); 12732 12733 //First delete all devices for this user, then add the (new) onces 12734 m_sql.safe_query("DELETE FROM SharedDevices WHERE (SharedUserID == '%q')", idx.c_str()); 12735 12736 int nDevices = static_cast<int>(strarray.size()); 12737 for (int ii = 0; ii < nDevices; ii++) 12738 { 12739 m_sql.safe_query("INSERT INTO SharedDevices (SharedUserID,DeviceRowID) VALUES ('%q','%q')", idx.c_str(), strarray[ii].c_str()); 12740 } 12741 LoadUsers(); 12742 } 12743 RType_SetUsed(WebEmSession & session,const request & req,Json::Value & root)12744 void CWebServer::RType_SetUsed(WebEmSession & session, const request& req, Json::Value &root) 12745 { 12746 if (session.rights != 2) 12747 { 12748 session.reply_status = reply::forbidden; 12749 return; //Only admin user allowed 12750 } 12751 12752 std::string idx = request::findValue(&req, "idx"); 12753 std::string deviceid = request::findValue(&req, "deviceid"); 12754 std::string name = HTMLSanitizer::Sanitize(request::findValue(&req, "name")); 12755 std::string description = HTMLSanitizer::Sanitize(request::findValue(&req, "description")); 12756 std::string sused = request::findValue(&req, "used"); 12757 std::string sswitchtype = request::findValue(&req, "switchtype"); 12758 std::string maindeviceidx = request::findValue(&req, "maindeviceidx"); 12759 std::string addjvalue = request::findValue(&req, "addjvalue"); 12760 std::string addjmulti = request::findValue(&req, "addjmulti"); 12761 std::string addjvalue2 = request::findValue(&req, "addjvalue2"); 12762 std::string addjmulti2 = request::findValue(&req, "addjmulti2"); 12763 std::string setPoint = request::findValue(&req, "setpoint"); 12764 std::string state = request::findValue(&req, "state"); 12765 std::string mode = request::findValue(&req, "mode"); 12766 std::string until = request::findValue(&req, "until"); 12767 std::string clock = request::findValue(&req, "clock"); 12768 std::string tmode = request::findValue(&req, "tmode"); 12769 std::string fmode = request::findValue(&req, "fmode"); 12770 std::string sCustomImage = request::findValue(&req, "customimage"); 12771 12772 std::string strunit = request::findValue(&req, "unit"); 12773 std::string strParam1 = HTMLSanitizer::Sanitize(base64_decode(request::findValue(&req, "strparam1"))); 12774 std::string strParam2 = HTMLSanitizer::Sanitize(base64_decode(request::findValue(&req, "strparam2"))); 12775 std::string tmpstr = request::findValue(&req, "protected"); 12776 bool bHasstrParam1 = request::hasValue(&req, "strparam1"); 12777 int iProtected = (tmpstr == "true") ? 1 : 0; 12778 12779 std::string sOptions = HTMLSanitizer::Sanitize(base64_decode(request::findValue(&req, "options"))); 12780 std::string devoptions = HTMLSanitizer::Sanitize(CURLEncode::URLDecode(request::findValue(&req, "devoptions"))); 12781 std::string EnergyMeterMode = CURLEncode::URLDecode(request::findValue(&req, "EnergyMeterMode")); 12782 12783 char szTmp[200]; 12784 12785 bool bHaveUser = (session.username != ""); 12786 //int iUser = -1; 12787 if (bHaveUser) 12788 { 12789 //iUser = FindUser(session.username.c_str()); 12790 } 12791 12792 int switchtype = -1; 12793 if (sswitchtype != "") 12794 switchtype = atoi(sswitchtype.c_str()); 12795 12796 if ((idx.empty()) || (sused.empty())) 12797 return; 12798 int used = (sused == "true") ? 1 : 0; 12799 if (maindeviceidx != "") 12800 used = 0; 12801 12802 int CustomImage = 0; 12803 if (sCustomImage != "") 12804 CustomImage = atoi(sCustomImage.c_str()); 12805 12806 //Strip trailing spaces in 'name' 12807 name = stdstring_trim(name); 12808 12809 //Strip trailing spaces in 'description' 12810 description = stdstring_trim(description); 12811 12812 std::vector<std::vector<std::string> > result; 12813 12814 result = m_sql.safe_query("SELECT Type,SubType,HardwareID FROM DeviceStatus WHERE (ID == '%q')", idx.c_str()); 12815 if (result.empty()) 12816 return; 12817 std::vector<std::string> sd = result[0]; 12818 12819 unsigned char dType = atoi(sd[0].c_str()); 12820 //unsigned char dSubType=atoi(sd[1].c_str()); 12821 int HwdID = atoi(sd[2].c_str()); 12822 std::string sHwdID = sd[2]; 12823 12824 if (setPoint != "" || state != "") 12825 { 12826 double tempcelcius = atof(setPoint.c_str()); 12827 if (m_sql.m_tempunit == TEMPUNIT_F) 12828 { 12829 //Convert back to Celsius 12830 tempcelcius = ConvertToCelsius(tempcelcius); 12831 } 12832 sprintf(szTmp, "%.2f", tempcelcius); 12833 12834 if (dType != pTypeEvohomeZone && dType != pTypeEvohomeWater)//sql update now done in setsetpoint for evohome devices 12835 { 12836 m_sql.safe_query("UPDATE DeviceStatus SET Used=%d, sValue='%q' WHERE (ID == '%q')", 12837 used, szTmp, idx.c_str()); 12838 } 12839 } 12840 if (name.empty()) 12841 { 12842 m_sql.safe_query("UPDATE DeviceStatus SET Used=%d WHERE (ID == '%q')", 12843 used, idx.c_str()); 12844 } 12845 else 12846 { 12847 if (switchtype == -1) 12848 { 12849 m_sql.safe_query("UPDATE DeviceStatus SET Used=%d, Name='%q', Description='%q' WHERE (ID == '%q')", 12850 used, name.c_str(), description.c_str(), idx.c_str()); 12851 } 12852 else 12853 { 12854 m_sql.safe_query( 12855 "UPDATE DeviceStatus SET Used=%d, Name='%q', Description='%q', SwitchType=%d, CustomImage=%d WHERE (ID == '%q')", 12856 used, name.c_str(), description.c_str(), switchtype, CustomImage, idx.c_str()); 12857 } 12858 } 12859 12860 if (bHasstrParam1) 12861 { 12862 m_sql.safe_query("UPDATE DeviceStatus SET StrParam1='%q', StrParam2='%q' WHERE (ID == '%q')", 12863 strParam1.c_str(), strParam2.c_str(), idx.c_str()); 12864 } 12865 12866 m_sql.safe_query("UPDATE DeviceStatus SET Protected=%d WHERE (ID == '%q')", iProtected, idx.c_str()); 12867 12868 if (!setPoint.empty() || !state.empty()) 12869 { 12870 int urights = 3; 12871 if (bHaveUser) 12872 { 12873 int iUser = FindUser(session.username.c_str()); 12874 if (iUser != -1) 12875 { 12876 urights = static_cast<int>(m_users[iUser].userrights); 12877 _log.Log(LOG_STATUS, "User: %s initiated a SetPoint command", m_users[iUser].Username.c_str()); 12878 } 12879 } 12880 if (urights < 1) 12881 return; 12882 if (dType == pTypeEvohomeWater) 12883 m_mainworker.SetSetPoint(idx, (state == "On") ? 1.0f : 0.0f, mode, until);//FIXME float not guaranteed precise? 12884 else if (dType == pTypeEvohomeZone) 12885 m_mainworker.SetSetPoint(idx, static_cast<float>(atof(setPoint.c_str())), mode, until); 12886 else 12887 m_mainworker.SetSetPoint(idx, static_cast<float>(atof(setPoint.c_str()))); 12888 } 12889 else if (!clock.empty()) 12890 { 12891 int urights = 3; 12892 if (bHaveUser) 12893 { 12894 int iUser = FindUser(session.username.c_str()); 12895 if (iUser != -1) 12896 { 12897 urights = static_cast<int>(m_users[iUser].userrights); 12898 _log.Log(LOG_STATUS, "User: %s initiated a SetClock command", m_users[iUser].Username.c_str()); 12899 } 12900 } 12901 if (urights < 1) 12902 return; 12903 m_mainworker.SetClock(idx, clock); 12904 } 12905 else if (!tmode.empty()) 12906 { 12907 int urights = 3; 12908 if (bHaveUser) 12909 { 12910 int iUser = FindUser(session.username.c_str()); 12911 if (iUser != -1) 12912 { 12913 urights = static_cast<int>(m_users[iUser].userrights); 12914 _log.Log(LOG_STATUS, "User: %s initiated a Thermostat Mode command", m_users[iUser].Username.c_str()); 12915 } 12916 } 12917 if (urights < 1) 12918 return; 12919 m_mainworker.SetZWaveThermostatMode(idx, atoi(tmode.c_str())); 12920 } 12921 else if (!fmode.empty()) 12922 { 12923 int urights = 3; 12924 if (bHaveUser) 12925 { 12926 int iUser = FindUser(session.username.c_str()); 12927 if (iUser != -1) 12928 { 12929 urights = static_cast<int>(m_users[iUser].userrights); 12930 _log.Log(LOG_STATUS, "User: %s initiated a Thermostat Fan Mode command", m_users[iUser].Username.c_str()); 12931 } 12932 } 12933 if (urights < 1) 12934 return; 12935 m_mainworker.SetZWaveThermostatFanMode(idx, atoi(fmode.c_str())); 12936 } 12937 12938 if (!strunit.empty()) 12939 { 12940 bool bUpdateUnit = true; 12941 #ifdef ENABLE_PYTHON 12942 //check if HW is plugin 12943 std::vector<std::vector<std::string> > result; 12944 result = m_sql.safe_query("SELECT Type FROM Hardware WHERE (ID == %d)", HwdID); 12945 if (!result.empty()) 12946 { 12947 std::vector<std::string> sd = result[0]; 12948 _eHardwareTypes Type = (_eHardwareTypes)atoi(sd[0].c_str()); 12949 if (Type == HTYPE_PythonPlugin) 12950 { 12951 bUpdateUnit = false; 12952 _log.Log(LOG_ERROR, "CWebServer::RType_SetUsed: Not allowed to change unit of device owned by plugin %u!", HwdID); 12953 } 12954 } 12955 #endif 12956 if (bUpdateUnit) 12957 { 12958 m_sql.safe_query("UPDATE DeviceStatus SET Unit='%q' WHERE (ID == '%q')", 12959 strunit.c_str(), idx.c_str()); 12960 } 12961 } 12962 //FIXME evohome ...we need the zone id to update the correct zone...but this should be ok as a generic call? 12963 if (!deviceid.empty()) 12964 { 12965 m_sql.safe_query("UPDATE DeviceStatus SET DeviceID='%q' WHERE (ID == '%q')", 12966 deviceid.c_str(), idx.c_str()); 12967 } 12968 if (!addjvalue.empty()) 12969 { 12970 double faddjvalue = atof(addjvalue.c_str()); 12971 m_sql.safe_query("UPDATE DeviceStatus SET AddjValue=%f WHERE (ID == '%q')", 12972 faddjvalue, idx.c_str()); 12973 } 12974 if (!addjmulti.empty()) 12975 { 12976 double faddjmulti = atof(addjmulti.c_str()); 12977 if (faddjmulti == 0) 12978 faddjmulti = 1; 12979 m_sql.safe_query("UPDATE DeviceStatus SET AddjMulti=%f WHERE (ID == '%q')", 12980 faddjmulti, idx.c_str()); 12981 } 12982 if (!addjvalue2.empty()) 12983 { 12984 double faddjvalue2 = atof(addjvalue2.c_str()); 12985 m_sql.safe_query("UPDATE DeviceStatus SET AddjValue2=%f WHERE (ID == '%q')", 12986 faddjvalue2, idx.c_str()); 12987 } 12988 if (!addjmulti2.empty()) 12989 { 12990 double faddjmulti2 = atof(addjmulti2.c_str()); 12991 if (faddjmulti2 == 0) 12992 faddjmulti2 = 1; 12993 m_sql.safe_query("UPDATE DeviceStatus SET AddjMulti2=%f WHERE (ID == '%q')", 12994 faddjmulti2, idx.c_str()); 12995 } 12996 if (!EnergyMeterMode.empty()) 12997 { 12998 auto options = m_sql.GetDeviceOptions(idx); 12999 options["EnergyMeterMode"] = EnergyMeterMode; 13000 uint64_t ullidx = std::strtoull(idx.c_str(), nullptr, 10); 13001 m_sql.SetDeviceOptions(ullidx, options); 13002 } 13003 13004 if (!devoptions.empty()) 13005 { 13006 m_sql.safe_query("UPDATE DeviceStatus SET Options='%q' WHERE (ID == '%q')", devoptions.c_str(), idx.c_str()); 13007 } 13008 13009 if (used == 0) 13010 { 13011 bool bRemoveSubDevices = (request::findValue(&req, "RemoveSubDevices") == "true"); 13012 13013 if (bRemoveSubDevices) 13014 { 13015 //if this device was a slave device, remove it 13016 m_sql.safe_query("DELETE FROM LightSubDevices WHERE (DeviceRowID == '%q')", idx.c_str()); 13017 } 13018 m_sql.safe_query("DELETE FROM LightSubDevices WHERE (ParentID == '%q')", idx.c_str()); 13019 13020 m_sql.safe_query("DELETE FROM Timers WHERE (DeviceRowID == '%q')", idx.c_str()); 13021 } 13022 13023 // Save device options 13024 if (!sOptions.empty()) 13025 { 13026 uint64_t ullidx = std::strtoull(idx.c_str(), nullptr, 10); 13027 m_sql.SetDeviceOptions(ullidx, m_sql.BuildDeviceOptions(sOptions, false)); 13028 } 13029 13030 if (maindeviceidx != "") 13031 { 13032 if (maindeviceidx != idx) 13033 { 13034 //this is a sub device for another light/switch 13035 //first check if it is not already a sub device 13036 result = m_sql.safe_query("SELECT ID FROM LightSubDevices WHERE (DeviceRowID=='%q') AND (ParentID =='%q')", 13037 idx.c_str(), maindeviceidx.c_str()); 13038 if (result.empty()) 13039 { 13040 //no it is not, add it 13041 m_sql.safe_query( 13042 "INSERT INTO LightSubDevices (DeviceRowID, ParentID) VALUES ('%q','%q')", 13043 idx.c_str(), 13044 maindeviceidx.c_str() 13045 ); 13046 } 13047 } 13048 } 13049 if ((used == 0) && (maindeviceidx.empty())) 13050 { 13051 //really remove it, including log etc 13052 m_sql.DeleteDevices(idx); 13053 } 13054 else 13055 { 13056 #ifdef ENABLE_PYTHON 13057 // Notify plugin framework about the change 13058 m_mainworker.m_pluginsystem.DeviceModified(atoi(idx.c_str())); 13059 #endif 13060 } 13061 if (!result.empty()) 13062 { 13063 root["status"] = "OK"; 13064 root["title"] = "SetUsed"; 13065 } 13066 if (m_sql.m_bEnableEventSystem) 13067 m_mainworker.m_eventsystem.GetCurrentStates(); 13068 } 13069 RType_Settings(WebEmSession & session,const request & req,Json::Value & root)13070 void CWebServer::RType_Settings(WebEmSession & session, const request& req, Json::Value &root) 13071 { 13072 std::vector<std::vector<std::string> > result; 13073 char szTmp[100]; 13074 13075 result = m_sql.safe_query("SELECT Key, nValue, sValue FROM Preferences"); 13076 if (result.empty()) 13077 return; 13078 root["status"] = "OK"; 13079 root["title"] = "settings"; 13080 #ifndef NOCLOUD 13081 root["cloudenabled"] = true; 13082 #else 13083 root["cloudenabled"] = false; 13084 #endif 13085 13086 for (const auto & itt : result) 13087 { 13088 std::vector<std::string> sd = itt; 13089 std::string Key = sd[0]; 13090 int nValue = atoi(sd[1].c_str()); 13091 std::string sValue = sd[2]; 13092 13093 if (Key == "Location") 13094 { 13095 std::vector<std::string> strarray; 13096 StringSplit(sValue, ";", strarray); 13097 13098 if (strarray.size() == 2) 13099 { 13100 root["Location"]["Latitude"] = strarray[0]; 13101 root["Location"]["Longitude"] = strarray[1]; 13102 } 13103 } 13104 /* RK: notification settings */ 13105 if (m_notifications.IsInConfig(Key)) { 13106 if (sValue.empty() && nValue > 0) { 13107 root[Key] = nValue; 13108 } 13109 else { 13110 root[Key] = sValue; 13111 } 13112 } 13113 else if (Key == "DashboardType") 13114 { 13115 root["DashboardType"] = nValue; 13116 } 13117 else if (Key == "MobileType") 13118 { 13119 root["MobileType"] = nValue; 13120 } 13121 else if (Key == "LightHistoryDays") 13122 { 13123 root["LightHistoryDays"] = nValue; 13124 } 13125 else if (Key == "5MinuteHistoryDays") 13126 { 13127 root["ShortLogDays"] = nValue; 13128 } 13129 else if (Key == "ShortLogInterval") 13130 { 13131 root["ShortLogInterval"] = nValue; 13132 } 13133 else if (Key == "WebUserName") 13134 { 13135 root["WebUserName"] = base64_decode(sValue); 13136 } 13137 //else if (Key == "WebPassword") 13138 //{ 13139 // root["WebPassword"] = sValue; 13140 //} 13141 else if (Key == "SecPassword") 13142 { 13143 root["SecPassword"] = sValue; 13144 } 13145 else if (Key == "ProtectionPassword") 13146 { 13147 root["ProtectionPassword"] = sValue; 13148 } 13149 else if (Key == "WebLocalNetworks") 13150 { 13151 root["WebLocalNetworks"] = sValue; 13152 } 13153 else if (Key == "WebRemoteProxyIPs") 13154 { 13155 root["WebRemoteProxyIPs"] = sValue; 13156 } 13157 else if (Key == "RandomTimerFrame") 13158 { 13159 root["RandomTimerFrame"] = nValue; 13160 } 13161 else if (Key == "MeterDividerEnergy") 13162 { 13163 root["EnergyDivider"] = nValue; 13164 } 13165 else if (Key == "MeterDividerGas") 13166 { 13167 root["GasDivider"] = nValue; 13168 } 13169 else if (Key == "MeterDividerWater") 13170 { 13171 root["WaterDivider"] = nValue; 13172 } 13173 else if (Key == "ElectricVoltage") 13174 { 13175 root["ElectricVoltage"] = nValue; 13176 } 13177 else if (Key == "CM113DisplayType") 13178 { 13179 root["CM113DisplayType"] = nValue; 13180 } 13181 else if (Key == "UseAutoUpdate") 13182 { 13183 root["UseAutoUpdate"] = nValue; 13184 } 13185 else if (Key == "UseAutoBackup") 13186 { 13187 root["UseAutoBackup"] = nValue; 13188 } 13189 else if (Key == "Rego6XXType") 13190 { 13191 root["Rego6XXType"] = nValue; 13192 } 13193 else if (Key == "CostEnergy") 13194 { 13195 sprintf(szTmp, "%.4f", (float)(nValue) / 10000.0f); 13196 root["CostEnergy"] = szTmp; 13197 } 13198 else if (Key == "CostEnergyT2") 13199 { 13200 sprintf(szTmp, "%.4f", (float)(nValue) / 10000.0f); 13201 root["CostEnergyT2"] = szTmp; 13202 } 13203 else if (Key == "CostEnergyR1") 13204 { 13205 sprintf(szTmp, "%.4f", (float)(nValue) / 10000.0f); 13206 root["CostEnergyR1"] = szTmp; 13207 } 13208 else if (Key == "CostEnergyR2") 13209 { 13210 sprintf(szTmp, "%.4f", (float)(nValue) / 10000.0f); 13211 root["CostEnergyR2"] = szTmp; 13212 } 13213 else if (Key == "CostGas") 13214 { 13215 sprintf(szTmp, "%.4f", (float)(nValue) / 10000.0f); 13216 root["CostGas"] = szTmp; 13217 } 13218 else if (Key == "CostWater") 13219 { 13220 sprintf(szTmp, "%.4f", (float)(nValue) / 10000.0f); 13221 root["CostWater"] = szTmp; 13222 } 13223 else if (Key == "ActiveTimerPlan") 13224 { 13225 root["ActiveTimerPlan"] = nValue; 13226 } 13227 else if (Key == "DoorbellCommand") 13228 { 13229 root["DoorbellCommand"] = nValue; 13230 } 13231 else if (Key == "SmartMeterType") 13232 { 13233 root["SmartMeterType"] = nValue; 13234 } 13235 else if (Key == "EnableTabFloorplans") 13236 { 13237 root["EnableTabFloorplans"] = nValue; 13238 } 13239 else if (Key == "EnableTabLights") 13240 { 13241 root["EnableTabLights"] = nValue; 13242 } 13243 else if (Key == "EnableTabTemp") 13244 { 13245 root["EnableTabTemp"] = nValue; 13246 } 13247 else if (Key == "EnableTabWeather") 13248 { 13249 root["EnableTabWeather"] = nValue; 13250 } 13251 else if (Key == "EnableTabUtility") 13252 { 13253 root["EnableTabUtility"] = nValue; 13254 } 13255 else if (Key == "EnableTabScenes") 13256 { 13257 root["EnableTabScenes"] = nValue; 13258 } 13259 else if (Key == "EnableTabCustom") 13260 { 13261 root["EnableTabCustom"] = nValue; 13262 } 13263 else if (Key == "NotificationSensorInterval") 13264 { 13265 root["NotificationSensorInterval"] = nValue; 13266 } 13267 else if (Key == "NotificationSwitchInterval") 13268 { 13269 root["NotificationSwitchInterval"] = nValue; 13270 } 13271 else if (Key == "RemoteSharedPort") 13272 { 13273 root["RemoteSharedPort"] = nValue; 13274 } 13275 else if (Key == "Language") 13276 { 13277 root["Language"] = sValue; 13278 } 13279 else if (Key == "Title") 13280 { 13281 root["Title"] = sValue; 13282 } 13283 else if (Key == "WindUnit") 13284 { 13285 root["WindUnit"] = nValue; 13286 } 13287 else if (Key == "TempUnit") 13288 { 13289 root["TempUnit"] = nValue; 13290 } 13291 else if (Key == "WeightUnit") 13292 { 13293 root["WeightUnit"] = nValue; 13294 } 13295 else if (Key == "AuthenticationMethod") 13296 { 13297 root["AuthenticationMethod"] = nValue; 13298 } 13299 else if (Key == "ReleaseChannel") 13300 { 13301 root["ReleaseChannel"] = nValue; 13302 } 13303 else if (Key == "RaspCamParams") 13304 { 13305 root["RaspCamParams"] = sValue; 13306 } 13307 else if (Key == "UVCParams") 13308 { 13309 root["UVCParams"] = sValue; 13310 } 13311 else if (Key == "AcceptNewHardware") 13312 { 13313 root["AcceptNewHardware"] = nValue; 13314 } 13315 else if (Key == "HideDisabledHardwareSensors") 13316 { 13317 root["HideDisabledHardwareSensors"] = nValue; 13318 } 13319 else if (Key == "ShowUpdateEffect") 13320 { 13321 root["ShowUpdateEffect"] = nValue; 13322 } 13323 else if (Key == "DegreeDaysBaseTemperature") 13324 { 13325 root["DegreeDaysBaseTemperature"] = sValue; 13326 } 13327 else if (Key == "EnableEventScriptSystem") 13328 { 13329 root["EnableEventScriptSystem"] = nValue; 13330 } 13331 else if (Key == "EventSystemLogFullURL") 13332 { 13333 root["EventSystemLogFullURL"] = nValue; 13334 } 13335 else if (Key == "DisableDzVentsSystem") 13336 { 13337 root["DisableDzVentsSystem"] = nValue; 13338 } 13339 else if (Key == "DzVentsLogLevel") 13340 { 13341 root["DzVentsLogLevel"] = nValue; 13342 } 13343 else if (Key == "LogEventScriptTrigger") 13344 { 13345 root["LogEventScriptTrigger"] = nValue; 13346 } 13347 else if (Key == "(1WireSensorPollPeriod") 13348 { 13349 root["1WireSensorPollPeriod"] = nValue; 13350 } 13351 else if (Key == "(1WireSwitchPollPeriod") 13352 { 13353 root["1WireSwitchPollPeriod"] = nValue; 13354 } 13355 else if (Key == "SecOnDelay") 13356 { 13357 root["SecOnDelay"] = nValue; 13358 } 13359 else if (Key == "AllowWidgetOrdering") 13360 { 13361 root["AllowWidgetOrdering"] = nValue; 13362 } 13363 else if (Key == "FloorplanPopupDelay") 13364 { 13365 root["FloorplanPopupDelay"] = nValue; 13366 } 13367 else if (Key == "FloorplanFullscreenMode") 13368 { 13369 root["FloorplanFullscreenMode"] = nValue; 13370 } 13371 else if (Key == "FloorplanAnimateZoom") 13372 { 13373 root["FloorplanAnimateZoom"] = nValue; 13374 } 13375 else if (Key == "FloorplanShowSensorValues") 13376 { 13377 root["FloorplanShowSensorValues"] = nValue; 13378 } 13379 else if (Key == "FloorplanShowSwitchValues") 13380 { 13381 root["FloorplanShowSwitchValues"] = nValue; 13382 } 13383 else if (Key == "FloorplanShowSceneNames") 13384 { 13385 root["FloorplanShowSceneNames"] = nValue; 13386 } 13387 else if (Key == "FloorplanRoomColour") 13388 { 13389 root["FloorplanRoomColour"] = sValue; 13390 } 13391 else if (Key == "FloorplanActiveOpacity") 13392 { 13393 root["FloorplanActiveOpacity"] = nValue; 13394 } 13395 else if (Key == "FloorplanInactiveOpacity") 13396 { 13397 root["FloorplanInactiveOpacity"] = nValue; 13398 } 13399 else if (Key == "SensorTimeout") 13400 { 13401 root["SensorTimeout"] = nValue; 13402 } 13403 else if (Key == "BatteryLowNotification") 13404 { 13405 root["BatterLowLevel"] = nValue; 13406 } 13407 else if (Key == "WebTheme") 13408 { 13409 root["WebTheme"] = sValue; 13410 } 13411 #ifndef NOCLOUD 13412 else if (Key == "MyDomoticzInstanceId") { 13413 root["MyDomoticzInstanceId"] = sValue; 13414 } 13415 else if (Key == "MyDomoticzUserId") { 13416 root["MyDomoticzUserId"] = sValue; 13417 } 13418 else if (Key == "MyDomoticzPassword") { 13419 root["MyDomoticzPassword"] = sValue; 13420 } 13421 else if (Key == "MyDomoticzSubsystems") { 13422 root["MyDomoticzSubsystems"] = nValue; 13423 } 13424 #endif 13425 else if (Key == "MyDomoticzSubsystems") { 13426 root["MyDomoticzSubsystems"] = nValue; 13427 } 13428 else if (Key == "SendErrorsAsNotification") { 13429 root["SendErrorsAsNotification"] = nValue; 13430 } 13431 else if (Key == "DeltaTemperatureLog") { 13432 root[Key] = sValue; 13433 } 13434 else if (Key == "IFTTTEnabled") { 13435 root["IFTTTEnabled"] = nValue; 13436 } 13437 else if (Key == "IFTTTAPI") { 13438 root["IFTTTAPI"] = sValue; 13439 } 13440 } 13441 } 13442 RType_LightLog(WebEmSession & session,const request & req,Json::Value & root)13443 void CWebServer::RType_LightLog(WebEmSession & session, const request& req, Json::Value &root) 13444 { 13445 uint64_t idx = 0; 13446 if (request::findValue(&req, "idx") != "") 13447 { 13448 idx = std::strtoull(request::findValue(&req, "idx").c_str(), nullptr, 10); 13449 } 13450 std::vector<std::vector<std::string> > result; 13451 //First get Device Type/SubType 13452 result = m_sql.safe_query("SELECT Type, SubType, SwitchType, Options FROM DeviceStatus WHERE (ID == %" PRIu64 ")", 13453 idx); 13454 if (result.empty()) 13455 return; 13456 13457 unsigned char dType = atoi(result[0][0].c_str()); 13458 unsigned char dSubType = atoi(result[0][1].c_str()); 13459 _eSwitchType switchtype = (_eSwitchType)atoi(result[0][2].c_str()); 13460 std::map<std::string, std::string> options = m_sql.BuildDeviceOptions(result[0][3].c_str()); 13461 13462 if ( 13463 (dType != pTypeLighting1) && 13464 (dType != pTypeLighting2) && 13465 (dType != pTypeLighting3) && 13466 (dType != pTypeLighting4) && 13467 (dType != pTypeLighting5) && 13468 (dType != pTypeLighting6) && 13469 (dType != pTypeFan) && 13470 (dType != pTypeColorSwitch) && 13471 (dType != pTypeSecurity1) && 13472 (dType != pTypeSecurity2) && 13473 (dType != pTypeEvohome) && 13474 (dType != pTypeEvohomeRelay) && 13475 (dType != pTypeCurtain) && 13476 (dType != pTypeBlinds) && 13477 (dType != pTypeRFY) && 13478 (dType != pTypeRego6XXValue) && 13479 (dType != pTypeChime) && 13480 (dType != pTypeThermostat2) && 13481 (dType != pTypeThermostat3) && 13482 (dType != pTypeThermostat4) && 13483 (dType != pTypeRemote) && 13484 (dType != pTypeGeneralSwitch) && 13485 (dType != pTypeHomeConfort) && 13486 (dType != pTypeFS20) && 13487 (!((dType == pTypeRadiator1) && (dSubType == sTypeSmartwaresSwitchRadiator))) && 13488 (dType != pTypeHunter) 13489 ) 13490 return; //no light device! we should not be here! 13491 13492 root["status"] = "OK"; 13493 root["title"] = "LightLog"; 13494 13495 result = m_sql.safe_query("SELECT ROWID, nValue, sValue, User, Date FROM LightingLog WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date DESC", idx); 13496 if (!result.empty()) 13497 { 13498 std::map<std::string, std::string> selectorStatuses; 13499 if (switchtype == STYPE_Selector) { 13500 GetSelectorSwitchStatuses(options, selectorStatuses); 13501 } 13502 13503 int ii = 0; 13504 for (const auto & itt : result) 13505 { 13506 std::vector<std::string> sd = itt; 13507 13508 std::string lidx = sd.at(0); 13509 int nValue = atoi(sd.at(1).c_str()); 13510 std::string sValue = sd.at(2); 13511 std::string sUser = sd.at(3); 13512 std::string ldate = sd.at(4); 13513 13514 //add light details 13515 std::string lstatus; 13516 std::string ldata; 13517 int llevel = 0; 13518 bool bHaveDimmer = false; 13519 bool bHaveSelector = false; 13520 bool bHaveGroupCmd = false; 13521 int maxDimLevel = 0; 13522 13523 if (switchtype == STYPE_Media) { 13524 if (sValue == "0") continue; //skip 0-values in log for MediaPlayers 13525 lstatus = sValue; 13526 ldata = lstatus; 13527 } 13528 else if (switchtype == STYPE_Selector) 13529 { 13530 if (ii == 0) { 13531 bHaveSelector = true; 13532 maxDimLevel = selectorStatuses.size(); 13533 } 13534 if (!selectorStatuses.empty()) { 13535 13536 std::string sLevel = selectorStatuses[sValue]; 13537 ldata = sLevel; 13538 lstatus = "Set Level: " + sLevel; 13539 llevel = atoi(sValue.c_str()); 13540 } 13541 } 13542 else { 13543 GetLightStatus(dType, dSubType, switchtype, nValue, sValue, lstatus, llevel, bHaveDimmer, maxDimLevel, bHaveGroupCmd); 13544 ldata = lstatus; 13545 } 13546 13547 if (ii == 0) 13548 { 13549 //Log these parameters once 13550 root["HaveDimmer"] = bHaveDimmer; 13551 root["result"][ii]["MaxDimLevel"] = maxDimLevel; 13552 root["HaveGroupCmd"] = bHaveGroupCmd; 13553 root["HaveSelector"] = bHaveSelector; 13554 } 13555 13556 //Corrent names for certain switch types 13557 switch (switchtype) 13558 { 13559 case STYPE_Contact: 13560 ldata = (ldata == "On") ? "Open" : "Closed"; 13561 break; 13562 case STYPE_DoorContact: 13563 ldata = (ldata == "On") ? "Open" : "Closed"; 13564 break; 13565 case STYPE_DoorLock: 13566 ldata = (ldata == "On") ? "Locked" : "Unlocked"; 13567 break; 13568 case STYPE_DoorLockInverted: 13569 ldata = (ldata == "On") ? "Unlocked" : "Locked"; 13570 break; 13571 case STYPE_Blinds: 13572 case STYPE_VenetianBlindsEU: 13573 case STYPE_VenetianBlindsUS: 13574 ldata = (ldata == "On") ? "Closed" : "Open"; 13575 break; 13576 case STYPE_BlindsInverted: 13577 ldata = (ldata == "On") ? "Open" : "Closed"; 13578 break; 13579 case STYPE_BlindsPercentage: 13580 if ((ldata == "On") || (ldata == "Off")) 13581 { 13582 ldata = (ldata == "On") ? "Closed" : "Open"; 13583 } 13584 break; 13585 case STYPE_BlindsPercentageInverted: 13586 if ((ldata == "On") || (ldata == "Off")) 13587 { 13588 ldata = (ldata == "On") ? "Open" : "Closed"; 13589 } 13590 break; 13591 } 13592 13593 root["result"][ii]["idx"] = lidx; 13594 root["result"][ii]["Date"] = ldate; 13595 root["result"][ii]["Data"] = ldata; 13596 root["result"][ii]["Status"] = lstatus; 13597 root["result"][ii]["Level"] = llevel; 13598 root["result"][ii]["User"] = sUser; 13599 ii++; 13600 } 13601 } 13602 } 13603 RType_TextLog(WebEmSession & session,const request & req,Json::Value & root)13604 void CWebServer::RType_TextLog(WebEmSession & session, const request& req, Json::Value &root) 13605 { 13606 uint64_t idx = 0; 13607 if (request::findValue(&req, "idx") != "") 13608 { 13609 idx = std::strtoull(request::findValue(&req, "idx").c_str(), nullptr, 10); 13610 } 13611 std::vector<std::vector<std::string> > result; 13612 13613 root["status"] = "OK"; 13614 root["title"] = "TextLog"; 13615 13616 result = m_sql.safe_query("SELECT ROWID, sValue, User, Date FROM LightingLog WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date DESC", 13617 idx); 13618 if (!result.empty()) 13619 { 13620 int ii = 0; 13621 for (const auto & itt : result) 13622 { 13623 std::vector<std::string> sd = itt; 13624 13625 root["result"][ii]["idx"] = sd[0]; 13626 root["result"][ii]["Data"] = sd[1]; 13627 root["result"][ii]["User"] = sd[2]; 13628 root["result"][ii]["Date"] = sd[3]; 13629 ii++; 13630 } 13631 } 13632 } 13633 RType_SceneLog(WebEmSession & session,const request & req,Json::Value & root)13634 void CWebServer::RType_SceneLog(WebEmSession & session, const request& req, Json::Value &root) 13635 { 13636 uint64_t idx = 0; 13637 if (request::findValue(&req, "idx") != "") 13638 { 13639 idx = std::strtoull(request::findValue(&req, "idx").c_str(), nullptr, 10); 13640 } 13641 std::vector<std::vector<std::string> > result; 13642 13643 root["status"] = "OK"; 13644 root["title"] = "SceneLog"; 13645 13646 result = m_sql.safe_query("SELECT ROWID, nValue, User, Date FROM SceneLog WHERE (SceneRowID==%" PRIu64 ") ORDER BY Date DESC", idx); 13647 if (!result.empty()) 13648 { 13649 int ii = 0; 13650 for (const auto & itt : result) 13651 { 13652 std::vector<std::string> sd = itt; 13653 13654 root["result"][ii]["idx"] = sd[0]; 13655 int nValue = atoi(sd[1].c_str()); 13656 root["result"][ii]["Data"] = (nValue == 0) ? "Off" : "On"; 13657 root["result"][ii]["User"] = sd[2]; 13658 root["result"][ii]["Date"] = sd[3]; 13659 ii++; 13660 } 13661 } 13662 } 13663 RType_HandleGraph(WebEmSession & session,const request & req,Json::Value & root)13664 void CWebServer::RType_HandleGraph(WebEmSession & session, const request& req, Json::Value &root) 13665 { 13666 uint64_t idx = 0; 13667 if (request::findValue(&req, "idx") != "") 13668 { 13669 idx = std::strtoull(request::findValue(&req, "idx").c_str(), nullptr, 10); 13670 } 13671 13672 std::vector<std::vector<std::string> > result; 13673 char szTmp[300]; 13674 13675 std::string sensor = request::findValue(&req, "sensor"); 13676 if (sensor == "") 13677 return; 13678 std::string srange = request::findValue(&req, "range"); 13679 if (srange == "") 13680 return; 13681 13682 time_t now = mytime(NULL); 13683 struct tm tm1; 13684 localtime_r(&now, &tm1); 13685 13686 result = m_sql.safe_query("SELECT Type, SubType, SwitchType, AddjValue, AddjMulti, AddjValue2, Options FROM DeviceStatus WHERE (ID == %" PRIu64 ")", 13687 idx); 13688 if (result.empty()) 13689 return; 13690 13691 unsigned char dType = atoi(result[0][0].c_str()); 13692 unsigned char dSubType = atoi(result[0][1].c_str()); 13693 _eMeterType metertype = (_eMeterType)atoi(result[0][2].c_str()); 13694 if ( 13695 (dType == pTypeP1Power) || 13696 (dType == pTypeENERGY) || 13697 (dType == pTypePOWER) || 13698 (dType == pTypeCURRENTENERGY) || 13699 ((dType == pTypeGeneral) && (dSubType == sTypeKwh)) 13700 ) 13701 { 13702 metertype = MTYPE_ENERGY; 13703 } 13704 else if (dType == pTypeP1Gas) 13705 metertype = MTYPE_GAS; 13706 else if ((dType == pTypeRego6XXValue) && (dSubType == sTypeRego6XXCounter)) 13707 metertype = MTYPE_COUNTER; 13708 13709 // Special case of managed counter: Usage instead of Value in Meter table, and we don't want to calculate last value 13710 bool bIsManagedCounter = (dType == pTypeGeneral) && (dSubType == sTypeManagedCounter); 13711 13712 double AddjValue = atof(result[0][3].c_str()); 13713 double AddjMulti = atof(result[0][4].c_str()); 13714 double AddjValue2 = atof(result[0][5].c_str()); 13715 std::string sOptions = result[0][6].c_str(); 13716 std::map<std::string, std::string> options = m_sql.BuildDeviceOptions(sOptions); 13717 13718 float divider = m_sql.GetCounterDivider(int(metertype), int(dType), float(AddjValue2)); 13719 13720 std::string dbasetable = ""; 13721 if (srange == "day") { 13722 if (sensor == "temp") 13723 dbasetable = "Temperature"; 13724 else if (sensor == "rain") 13725 dbasetable = "Rain"; 13726 else if (sensor == "Percentage") 13727 dbasetable = "Percentage"; 13728 else if (sensor == "fan") 13729 dbasetable = "Fan"; 13730 else if (sensor == "counter") 13731 { 13732 if ((dType == pTypeP1Power) || (dType == pTypeCURRENT) || (dType == pTypeCURRENTENERGY)) 13733 { 13734 dbasetable = "MultiMeter"; 13735 } 13736 else 13737 { 13738 dbasetable = "Meter"; 13739 } 13740 } 13741 else if ((sensor == "wind") || (sensor == "winddir")) 13742 dbasetable = "Wind"; 13743 else if (sensor == "uv") 13744 dbasetable = "UV"; 13745 else 13746 return; 13747 } 13748 else 13749 { 13750 //week,year,month 13751 if (sensor == "temp") 13752 dbasetable = "Temperature_Calendar"; 13753 else if (sensor == "rain") 13754 dbasetable = "Rain_Calendar"; 13755 else if (sensor == "Percentage") 13756 dbasetable = "Percentage_Calendar"; 13757 else if (sensor == "fan") 13758 dbasetable = "Fan_Calendar"; 13759 else if (sensor == "counter") 13760 { 13761 if ( 13762 (dType == pTypeP1Power) || 13763 (dType == pTypeCURRENT) || 13764 (dType == pTypeCURRENTENERGY) || 13765 (dType == pTypeAirQuality) || 13766 ((dType == pTypeGeneral) && (dSubType == sTypeVisibility)) || 13767 ((dType == pTypeGeneral) && (dSubType == sTypeDistance)) || 13768 ((dType == pTypeGeneral) && (dSubType == sTypeSolarRadiation)) || 13769 ((dType == pTypeGeneral) && (dSubType == sTypeSoilMoisture)) || 13770 ((dType == pTypeGeneral) && (dSubType == sTypeLeafWetness)) || 13771 ((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorAD)) || 13772 ((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorVolt)) || 13773 ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) || 13774 ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) || 13775 ((dType == pTypeGeneral) && (dSubType == sTypePressure)) || 13776 ((dType == pTypeGeneral) && (dSubType == sTypeSoundLevel)) || 13777 (dType == pTypeLux) || 13778 (dType == pTypeWEIGHT) || 13779 (dType == pTypeUsage) 13780 ) 13781 dbasetable = "MultiMeter_Calendar"; 13782 else 13783 dbasetable = "Meter_Calendar"; 13784 } 13785 else if ((sensor == "wind") || (sensor == "winddir")) 13786 dbasetable = "Wind_Calendar"; 13787 else if (sensor == "uv") 13788 dbasetable = "UV_Calendar"; 13789 else 13790 return; 13791 } 13792 unsigned char tempsign = m_sql.m_tempsign[0]; 13793 int iPrev; 13794 13795 if (srange == "day") 13796 { 13797 if (sensor == "temp") { 13798 root["status"] = "OK"; 13799 root["title"] = "Graph " + sensor + " " + srange; 13800 13801 result = m_sql.safe_query("SELECT Temperature, Chill, Humidity, Barometer, Date, SetPoint FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 13802 if (!result.empty()) 13803 { 13804 int ii = 0; 13805 for (const auto & itt : result) 13806 { 13807 std::vector<std::string> sd = itt; 13808 13809 root["result"][ii]["d"] = sd[4].substr(0, 16); 13810 if ( 13811 (dType == pTypeRego6XXTemp) || 13812 (dType == pTypeTEMP) || 13813 (dType == pTypeTEMP_HUM) || 13814 (dType == pTypeTEMP_HUM_BARO) || 13815 (dType == pTypeTEMP_BARO) || 13816 ((dType == pTypeWIND) && (dSubType == sTypeWIND4)) || 13817 ((dType == pTypeUV) && (dSubType == sTypeUV3)) || 13818 (dType == pTypeThermostat1) || 13819 (dType == pTypeRadiator1) || 13820 ((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorTemp)) || 13821 ((dType == pTypeGeneral) && (dSubType == sTypeSystemTemp)) || 13822 ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) || 13823 ((dType == pTypeThermostat) && (dSubType == sTypeThermSetpoint)) || 13824 (dType == pTypeEvohomeZone) || 13825 (dType == pTypeEvohomeWater) 13826 ) 13827 { 13828 double tvalue = ConvertTemperature(atof(sd[0].c_str()), tempsign); 13829 root["result"][ii]["te"] = tvalue; 13830 } 13831 if ( 13832 ((dType == pTypeWIND) && (dSubType == sTypeWIND4)) || 13833 ((dType == pTypeWIND) && (dSubType == sTypeWINDNoTemp)) 13834 ) 13835 { 13836 double tvalue = ConvertTemperature(atof(sd[1].c_str()), tempsign); 13837 root["result"][ii]["ch"] = tvalue; 13838 } 13839 if ((dType == pTypeHUM) || (dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO)) 13840 { 13841 root["result"][ii]["hu"] = sd[2]; 13842 } 13843 if ( 13844 (dType == pTypeTEMP_HUM_BARO) || 13845 (dType == pTypeTEMP_BARO) || 13846 ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 13847 ) 13848 { 13849 if (dType == pTypeTEMP_HUM_BARO) 13850 { 13851 if (dSubType == sTypeTHBFloat) 13852 { 13853 sprintf(szTmp, "%.1f", atof(sd[3].c_str()) / 10.0f); 13854 root["result"][ii]["ba"] = szTmp; 13855 } 13856 else 13857 root["result"][ii]["ba"] = sd[3]; 13858 } 13859 else if (dType == pTypeTEMP_BARO) 13860 { 13861 sprintf(szTmp, "%.1f", atof(sd[3].c_str()) / 10.0f); 13862 root["result"][ii]["ba"] = szTmp; 13863 } 13864 else if ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 13865 { 13866 sprintf(szTmp, "%.1f", atof(sd[3].c_str()) / 10.0f); 13867 root["result"][ii]["ba"] = szTmp; 13868 } 13869 } 13870 if ((dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater)) 13871 { 13872 double se = ConvertTemperature(atof(sd[5].c_str()), tempsign); 13873 root["result"][ii]["se"] = se; 13874 } 13875 13876 ii++; 13877 } 13878 } 13879 } 13880 else if (sensor == "Percentage") { 13881 root["status"] = "OK"; 13882 root["title"] = "Graph " + sensor + " " + srange; 13883 13884 result = m_sql.safe_query("SELECT Percentage, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 13885 if (!result.empty()) 13886 { 13887 int ii = 0; 13888 for (const auto & itt : result) 13889 { 13890 std::vector<std::string> sd = itt; 13891 13892 root["result"][ii]["d"] = sd[1].substr(0, 16); 13893 root["result"][ii]["v"] = sd[0]; 13894 ii++; 13895 } 13896 } 13897 } 13898 else if (sensor == "fan") { 13899 root["status"] = "OK"; 13900 root["title"] = "Graph " + sensor + " " + srange; 13901 13902 result = m_sql.safe_query("SELECT Speed, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 13903 if (!result.empty()) 13904 { 13905 int ii = 0; 13906 for (const auto & itt : result) 13907 { 13908 std::vector<std::string> sd = itt; 13909 13910 root["result"][ii]["d"] = sd[1].substr(0, 16); 13911 root["result"][ii]["v"] = sd[0]; 13912 ii++; 13913 } 13914 } 13915 } 13916 13917 else if (sensor == "counter") 13918 { 13919 if (dType == pTypeP1Power) 13920 { 13921 root["status"] = "OK"; 13922 root["title"] = "Graph " + sensor + " " + srange; 13923 13924 result = m_sql.safe_query("SELECT Value1, Value2, Value3, Value4, Value5, Value6, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 13925 if (!result.empty()) 13926 { 13927 int ii = 0; 13928 bool bHaveDeliverd = false; 13929 bool bHaveFirstValue = false; 13930 long long lastUsage1, lastUsage2, lastDeliv1, lastDeliv2; 13931 time_t lastTime = 0; 13932 13933 long long firstUsage1 = 0; 13934 long long firstUsage2 = 0; 13935 long long firstDeliv1 = 0; 13936 long long firstDeliv2 = 0; 13937 13938 int nMeterType = 0; 13939 m_sql.GetPreferencesVar("SmartMeterType", nMeterType); 13940 13941 int lastDay = 0; 13942 13943 for (const auto & itt : result) 13944 { 13945 std::vector<std::string> sd = itt; 13946 13947 if (nMeterType == 0) 13948 { 13949 long long actUsage1 = std::strtoll(sd[0].c_str(), nullptr, 10); 13950 long long actUsage2 = std::strtoll(sd[4].c_str(), nullptr, 10); 13951 long long actDeliv1 = std::strtoll(sd[1].c_str(), nullptr, 10); 13952 long long actDeliv2 = std::strtoll(sd[5].c_str(), nullptr, 10); 13953 actDeliv1 = (actDeliv1 < 10) ? 0 : actDeliv1; 13954 actDeliv2 = (actDeliv2 < 10) ? 0 : actDeliv2; 13955 13956 std::string stime = sd[6]; 13957 struct tm ntime; 13958 time_t atime; 13959 ParseSQLdatetime(atime, ntime, stime, -1); 13960 if (lastDay != ntime.tm_mday) 13961 { 13962 lastDay = ntime.tm_mday; 13963 firstUsage1 = actUsage1; 13964 firstUsage2 = actUsage2; 13965 firstDeliv1 = actDeliv1; 13966 firstDeliv2 = actDeliv2; 13967 } 13968 13969 if (bHaveFirstValue) 13970 { 13971 long curUsage1 = (long)(actUsage1 - lastUsage1); 13972 long curUsage2 = (long)(actUsage2 - lastUsage2); 13973 long curDeliv1 = (long)(actDeliv1 - lastDeliv1); 13974 long curDeliv2 = (long)(actDeliv2 - lastDeliv2); 13975 13976 if ((curUsage1 < 0) || (curUsage1 > 100000)) 13977 curUsage1 = 0; 13978 if ((curUsage2 < 0) || (curUsage2 > 100000)) 13979 curUsage2 = 0; 13980 if ((curDeliv1 < 0) || (curDeliv1 > 100000)) 13981 curDeliv1 = 0; 13982 if ((curDeliv2 < 0) || (curDeliv2 > 100000)) 13983 curDeliv2 = 0; 13984 13985 float tdiff = static_cast<float>(difftime(atime, lastTime)); 13986 if (tdiff == 0) 13987 tdiff = 1; 13988 float tlaps = 3600.0f / tdiff; 13989 curUsage1 *= int(tlaps); 13990 curUsage2 *= int(tlaps); 13991 curDeliv1 *= int(tlaps); 13992 curDeliv2 *= int(tlaps); 13993 13994 root["result"][ii]["d"] = sd[6].substr(0, 16); 13995 13996 if ((curDeliv1 != 0) || (curDeliv2 != 0)) 13997 bHaveDeliverd = true; 13998 13999 sprintf(szTmp, "%ld", curUsage1); 14000 root["result"][ii]["v"] = szTmp; 14001 sprintf(szTmp, "%ld", curUsage2); 14002 root["result"][ii]["v2"] = szTmp; 14003 sprintf(szTmp, "%ld", curDeliv1); 14004 root["result"][ii]["r1"] = szTmp; 14005 sprintf(szTmp, "%ld", curDeliv2); 14006 root["result"][ii]["r2"] = szTmp; 14007 14008 long pUsage1 = (long)(actUsage1 - firstUsage1); 14009 long pUsage2 = (long)(actUsage2 - firstUsage2); 14010 14011 sprintf(szTmp, "%ld", pUsage1 + pUsage2); 14012 root["result"][ii]["eu"] = szTmp; 14013 if (bHaveDeliverd) 14014 { 14015 long pDeliv1 = (long)(actDeliv1 - firstDeliv1); 14016 long pDeliv2 = (long)(actDeliv2 - firstDeliv2); 14017 sprintf(szTmp, "%ld", pDeliv1 + pDeliv2); 14018 root["result"][ii]["eg"] = szTmp; 14019 } 14020 14021 ii++; 14022 } 14023 else 14024 { 14025 bHaveFirstValue = true; 14026 if ((ntime.tm_hour != 0) && (ntime.tm_min != 0)) 14027 { 14028 struct tm ltime; 14029 localtime_r(&atime, &tm1); 14030 getNoon(atime, ltime, ntime.tm_year + 1900, ntime.tm_mon + 1, ntime.tm_mday - 1); // We're only interested in finding the date 14031 int year = ltime.tm_year + 1900; 14032 int mon = ltime.tm_mon + 1; 14033 int day = ltime.tm_mday; 14034 sprintf(szTmp, "%04d-%02d-%02d", year, mon, day); 14035 std::vector<std::vector<std::string> > result2; 14036 result2 = m_sql.safe_query( 14037 "SELECT Counter1, Counter2, Counter3, Counter4 FROM Multimeter_Calendar WHERE (DeviceRowID==%" PRIu64 ") AND (Date=='%q')", 14038 idx, szTmp); 14039 if (!result2.empty()) 14040 { 14041 std::vector<std::string> sd = result2[0]; 14042 firstUsage1 = std::strtoll(sd[0].c_str(), nullptr, 10); 14043 firstDeliv1 = std::strtoll(sd[1].c_str(), nullptr, 10); 14044 firstUsage2 = std::strtoll(sd[2].c_str(), nullptr, 10); 14045 firstDeliv2 = std::strtoll(sd[3].c_str(), nullptr, 10); 14046 lastDay = ntime.tm_mday; 14047 } 14048 } 14049 14050 } 14051 lastUsage1 = actUsage1; 14052 lastUsage2 = actUsage2; 14053 lastDeliv1 = actDeliv1; 14054 lastDeliv2 = actDeliv2; 14055 lastTime = atime; 14056 } 14057 else 14058 { 14059 //this meter has no decimals, so return the use peaks 14060 root["result"][ii]["d"] = sd[6].substr(0, 16); 14061 14062 if (sd[3] != "0") 14063 bHaveDeliverd = true; 14064 root["result"][ii]["v"] = sd[2]; 14065 root["result"][ii]["r1"] = sd[3]; 14066 ii++; 14067 14068 } 14069 } 14070 if (bHaveDeliverd) 14071 { 14072 root["delivered"] = true; 14073 } 14074 } 14075 } 14076 else if (dType == pTypeAirQuality) 14077 {//day 14078 root["status"] = "OK"; 14079 root["title"] = "Graph " + sensor + " " + srange; 14080 14081 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14082 if (!result.empty()) 14083 { 14084 int ii = 0; 14085 for (const auto & itt : result) 14086 { 14087 std::vector<std::string> sd = itt; 14088 14089 root["result"][ii]["d"] = sd[1].substr(0, 16); 14090 root["result"][ii]["co2"] = sd[0]; 14091 ii++; 14092 } 14093 } 14094 } 14095 else if ((dType == pTypeGeneral) && ((dSubType == sTypeSoilMoisture) || (dSubType == sTypeLeafWetness))) 14096 {//day 14097 root["status"] = "OK"; 14098 root["title"] = "Graph " + sensor + " " + srange; 14099 14100 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14101 if (!result.empty()) 14102 { 14103 int ii = 0; 14104 for (const auto & itt : result) 14105 { 14106 std::vector<std::string> sd = itt; 14107 14108 root["result"][ii]["d"] = sd[1].substr(0, 16); 14109 root["result"][ii]["v"] = sd[0]; 14110 ii++; 14111 } 14112 } 14113 } 14114 else if ( 14115 ((dType == pTypeGeneral) && (dSubType == sTypeVisibility)) || 14116 ((dType == pTypeGeneral) && (dSubType == sTypeDistance)) || 14117 ((dType == pTypeGeneral) && (dSubType == sTypeSolarRadiation)) || 14118 ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) || 14119 ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) || 14120 ((dType == pTypeGeneral) && (dSubType == sTypePressure)) || 14121 ((dType == pTypeGeneral) && (dSubType == sTypeSoundLevel)) 14122 ) 14123 {//day 14124 root["status"] = "OK"; 14125 root["title"] = "Graph " + sensor + " " + srange; 14126 float vdiv = 10.0f; 14127 if ( 14128 ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) || 14129 ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) 14130 ) 14131 { 14132 vdiv = 1000.0f; 14133 } 14134 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14135 if (!result.empty()) 14136 { 14137 int ii = 0; 14138 for (const auto & itt : result) 14139 { 14140 std::vector<std::string> sd = itt; 14141 14142 root["result"][ii]["d"] = sd[1].substr(0, 16); 14143 float fValue = float(atof(sd[0].c_str())) / vdiv; 14144 if (metertype == 1) 14145 fValue *= 0.6214f; 14146 if ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) 14147 sprintf(szTmp, "%.3f", fValue); 14148 else if ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) 14149 sprintf(szTmp, "%.3f", fValue); 14150 else 14151 sprintf(szTmp, "%.1f", fValue); 14152 root["result"][ii]["v"] = szTmp; 14153 ii++; 14154 } 14155 } 14156 } 14157 else if ((dType == pTypeRFXSensor) && ((dSubType == sTypeRFXSensorAD) || (dSubType == sTypeRFXSensorVolt))) 14158 {//day 14159 root["status"] = "OK"; 14160 root["title"] = "Graph " + sensor + " " + srange; 14161 14162 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14163 if (!result.empty()) 14164 { 14165 int ii = 0; 14166 for (const auto & itt : result) 14167 { 14168 std::vector<std::string> sd = itt; 14169 14170 root["result"][ii]["d"] = sd[1].substr(0, 16); 14171 root["result"][ii]["v"] = sd[0]; 14172 ii++; 14173 } 14174 } 14175 } 14176 else if (dType == pTypeLux) 14177 {//day 14178 root["status"] = "OK"; 14179 root["title"] = "Graph " + sensor + " " + srange; 14180 14181 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14182 if (!result.empty()) 14183 { 14184 int ii = 0; 14185 for (const auto & itt : result) 14186 { 14187 std::vector<std::string> sd = itt; 14188 14189 root["result"][ii]["d"] = sd[1].substr(0, 16); 14190 root["result"][ii]["lux"] = sd[0]; 14191 ii++; 14192 } 14193 } 14194 } 14195 else if (dType == pTypeWEIGHT) 14196 {//day 14197 root["status"] = "OK"; 14198 root["title"] = "Graph " + sensor + " " + srange; 14199 14200 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14201 if (!result.empty()) 14202 { 14203 int ii = 0; 14204 for (const auto & itt : result) 14205 { 14206 std::vector<std::string> sd = itt; 14207 14208 root["result"][ii]["d"] = sd[1].substr(0, 16); 14209 sprintf(szTmp, "%.1f", m_sql.m_weightscale * atof(sd[0].c_str()) / 10.0f); 14210 root["result"][ii]["v"] = szTmp; 14211 ii++; 14212 } 14213 } 14214 } 14215 else if (dType == pTypeUsage) 14216 {//day 14217 root["status"] = "OK"; 14218 root["title"] = "Graph " + sensor + " " + srange; 14219 14220 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14221 if (!result.empty()) 14222 { 14223 int ii = 0; 14224 for (const auto & itt : result) 14225 { 14226 std::vector<std::string> sd = itt; 14227 14228 root["result"][ii]["d"] = sd[1].substr(0, 16); 14229 root["result"][ii]["u"] = atof(sd[0].c_str()) / 10.0f; 14230 ii++; 14231 } 14232 } 14233 } 14234 else if (dType == pTypeCURRENT) 14235 { 14236 root["status"] = "OK"; 14237 root["title"] = "Graph " + sensor + " " + srange; 14238 14239 //CM113 14240 int displaytype = 0; 14241 int voltage = 230; 14242 m_sql.GetPreferencesVar("CM113DisplayType", displaytype); 14243 m_sql.GetPreferencesVar("ElectricVoltage", voltage); 14244 14245 root["displaytype"] = displaytype; 14246 14247 result = m_sql.safe_query("SELECT Value1, Value2, Value3, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14248 if (!result.empty()) 14249 { 14250 int ii = 0; 14251 bool bHaveL1 = false; 14252 bool bHaveL2 = false; 14253 bool bHaveL3 = false; 14254 for (const auto & itt : result) 14255 { 14256 std::vector<std::string> sd = itt; 14257 14258 root["result"][ii]["d"] = sd[3].substr(0, 16); 14259 14260 float fval1 = static_cast<float>(atof(sd[0].c_str()) / 10.0f); 14261 float fval2 = static_cast<float>(atof(sd[1].c_str()) / 10.0f); 14262 float fval3 = static_cast<float>(atof(sd[2].c_str()) / 10.0f); 14263 14264 if (fval1 != 0) 14265 bHaveL1 = true; 14266 if (fval2 != 0) 14267 bHaveL2 = true; 14268 if (fval3 != 0) 14269 bHaveL3 = true; 14270 14271 if (displaytype == 0) 14272 { 14273 sprintf(szTmp, "%.1f", fval1); 14274 root["result"][ii]["v1"] = szTmp; 14275 sprintf(szTmp, "%.1f", fval2); 14276 root["result"][ii]["v2"] = szTmp; 14277 sprintf(szTmp, "%.1f", fval3); 14278 root["result"][ii]["v3"] = szTmp; 14279 } 14280 else 14281 { 14282 sprintf(szTmp, "%d", int(fval1*voltage)); 14283 root["result"][ii]["v1"] = szTmp; 14284 sprintf(szTmp, "%d", int(fval2*voltage)); 14285 root["result"][ii]["v2"] = szTmp; 14286 sprintf(szTmp, "%d", int(fval3*voltage)); 14287 root["result"][ii]["v3"] = szTmp; 14288 } 14289 ii++; 14290 } 14291 if ( 14292 (!bHaveL1) && 14293 (!bHaveL2) && 14294 (!bHaveL3) 14295 ) { 14296 root["haveL1"] = true; //show at least something 14297 } 14298 else { 14299 if (bHaveL1) 14300 root["haveL1"] = true; 14301 if (bHaveL2) 14302 root["haveL2"] = true; 14303 if (bHaveL3) 14304 root["haveL3"] = true; 14305 } 14306 } 14307 } 14308 else if (dType == pTypeCURRENTENERGY) 14309 { 14310 root["status"] = "OK"; 14311 root["title"] = "Graph " + sensor + " " + srange; 14312 14313 //CM113 14314 int displaytype = 0; 14315 int voltage = 230; 14316 m_sql.GetPreferencesVar("CM113DisplayType", displaytype); 14317 m_sql.GetPreferencesVar("ElectricVoltage", voltage); 14318 14319 root["displaytype"] = displaytype; 14320 14321 result = m_sql.safe_query("SELECT Value1, Value2, Value3, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14322 if (!result.empty()) 14323 { 14324 int ii = 0; 14325 bool bHaveL1 = false; 14326 bool bHaveL2 = false; 14327 bool bHaveL3 = false; 14328 for (const auto & itt : result) 14329 { 14330 std::vector<std::string> sd = itt; 14331 14332 root["result"][ii]["d"] = sd[3].substr(0, 16); 14333 14334 float fval1 = static_cast<float>(atof(sd[0].c_str()) / 10.0f); 14335 float fval2 = static_cast<float>(atof(sd[1].c_str()) / 10.0f); 14336 float fval3 = static_cast<float>(atof(sd[2].c_str()) / 10.0f); 14337 14338 if (fval1 != 0) 14339 bHaveL1 = true; 14340 if (fval2 != 0) 14341 bHaveL2 = true; 14342 if (fval3 != 0) 14343 bHaveL3 = true; 14344 14345 if (displaytype == 0) 14346 { 14347 sprintf(szTmp, "%.1f", fval1); 14348 root["result"][ii]["v1"] = szTmp; 14349 sprintf(szTmp, "%.1f", fval2); 14350 root["result"][ii]["v2"] = szTmp; 14351 sprintf(szTmp, "%.1f", fval3); 14352 root["result"][ii]["v3"] = szTmp; 14353 } 14354 else 14355 { 14356 sprintf(szTmp, "%d", int(fval1*voltage)); 14357 root["result"][ii]["v1"] = szTmp; 14358 sprintf(szTmp, "%d", int(fval2*voltage)); 14359 root["result"][ii]["v2"] = szTmp; 14360 sprintf(szTmp, "%d", int(fval3*voltage)); 14361 root["result"][ii]["v3"] = szTmp; 14362 } 14363 ii++; 14364 } 14365 if ( 14366 (!bHaveL1) && 14367 (!bHaveL2) && 14368 (!bHaveL3) 14369 ) { 14370 root["haveL1"] = true; //show at least something 14371 } 14372 else { 14373 if (bHaveL1) 14374 root["haveL1"] = true; 14375 if (bHaveL2) 14376 root["haveL2"] = true; 14377 if (bHaveL3) 14378 root["haveL3"] = true; 14379 } 14380 } 14381 } 14382 else if ((dType == pTypeENERGY) || (dType == pTypePOWER) || (dType == pTypeYouLess) || ((dType == pTypeGeneral) && (dSubType == sTypeKwh))) 14383 { 14384 root["status"] = "OK"; 14385 root["title"] = "Graph " + sensor + " " + srange; 14386 root["ValueQuantity"] = options["ValueQuantity"]; 14387 root["ValueUnits"] = options["ValueUnits"]; 14388 14389 //First check if we had any usage in the short log, if not, its probably a meter without usage 14390 bool bHaveUsage = true; 14391 result = m_sql.safe_query("SELECT MIN([Usage]), MAX([Usage]) FROM %s WHERE (DeviceRowID==%" PRIu64 ")", dbasetable.c_str(), idx); 14392 if (!result.empty()) 14393 { 14394 long long minValue = std::strtoll(result[0][0].c_str(), nullptr, 10); 14395 long long maxValue = std::strtoll(result[0][1].c_str(), nullptr, 10); 14396 if ((minValue == 0) && (maxValue == 0)) 14397 { 14398 bHaveUsage = false; 14399 } 14400 } 14401 14402 int ii = 0; 14403 result = m_sql.safe_query("SELECT Value,[Usage], Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14404 14405 int method = 0; 14406 std::string sMethod = request::findValue(&req, "method"); 14407 if (sMethod.size() > 0) 14408 method = atoi(sMethod.c_str()); 14409 if (bHaveUsage == false) 14410 method = 0; 14411 14412 if ((dType == pTypeYouLess) && ((metertype == MTYPE_ENERGY) || (metertype == MTYPE_ENERGY_GENERATED))) 14413 method = 1; 14414 14415 if (method != 0) 14416 { 14417 //realtime graph 14418 if ((dType == pTypeENERGY) || (dType == pTypePOWER)) 14419 divider /= 100.0f; 14420 } 14421 root["method"] = method; 14422 bool bHaveFirstValue = false; 14423 bool bHaveFirstRealValue = false; 14424 long long ulFirstRealValue = 0; 14425 long long ulFirstValue = 0; 14426 long long ulLastValue = 0; 14427 std::string LastDateTime = ""; 14428 14429 if (!result.empty()) 14430 { 14431 std::vector<std::vector<std::string> >::const_iterator itt; 14432 for (itt = result.begin(); itt!=result.end(); ++itt) 14433 { 14434 std::vector<std::string> sd = *itt; 14435 14436 //If method == 1, provide BOTH hourly and instant usage for combined graph 14437 { 14438 //bars / hour 14439 std::string actDateTimeHour = sd[2].substr(0, 13); 14440 long long actValue = std::strtoll(sd[0].c_str(), nullptr, 10); 14441 14442 if (actValue >= ulLastValue) 14443 ulLastValue = actValue; 14444 14445 if (actDateTimeHour != LastDateTime || ((method == 1) && (itt + 1 == result.end()))) 14446 { 14447 if (bHaveFirstValue) 14448 { 14449 //root["result"][ii]["d"] = LastDateTime + (method == 1 ? ":30" : ":00"); 14450 //^^ not necessarily bad, but is currently inconsistent with all other day graphs 14451 root["result"][ii]["d"] = LastDateTime + ":00"; 14452 14453 long long ulTotalValue = ulLastValue - ulFirstValue; 14454 if (ulTotalValue == 0) 14455 { 14456 //Could be the P1 Gas Meter, only transmits one every 1 a 2 hours 14457 ulTotalValue = ulLastValue - ulFirstRealValue; 14458 } 14459 ulFirstRealValue = ulLastValue; 14460 float TotalValue = float(ulTotalValue); 14461 switch (metertype) 14462 { 14463 case MTYPE_ENERGY: 14464 case MTYPE_ENERGY_GENERATED: 14465 sprintf(szTmp, "%.3f", (TotalValue / divider)*1000.0f); //from kWh -> Watt 14466 break; 14467 case MTYPE_GAS: 14468 sprintf(szTmp, "%.3f", TotalValue / divider); 14469 break; 14470 case MTYPE_WATER: 14471 sprintf(szTmp, "%.3f", TotalValue / divider); 14472 break; 14473 case MTYPE_COUNTER: 14474 sprintf(szTmp, "%.1f", TotalValue); 14475 break; 14476 default: 14477 strcpy(szTmp, "0"); 14478 break; 14479 } 14480 root["result"][ii][method == 1 ? "eu" : "v"] = szTmp; 14481 ii++; 14482 } 14483 LastDateTime = actDateTimeHour; 14484 bHaveFirstValue = false; 14485 } 14486 if (!bHaveFirstValue) 14487 { 14488 ulFirstValue = ulLastValue; 14489 bHaveFirstValue = true; 14490 } 14491 if (!bHaveFirstRealValue) 14492 { 14493 bHaveFirstRealValue = true; 14494 ulFirstRealValue = ulLastValue; 14495 } 14496 } 14497 14498 if (method == 1) 14499 { 14500 long long actValue = std::strtoll(sd[1].c_str(), nullptr, 10); 14501 14502 root["result"][ii]["d"] = sd[2].substr(0, 16); 14503 14504 float TotalValue = float(actValue); 14505 if ((dType == pTypeGeneral) && (dSubType == sTypeKwh)) 14506 TotalValue /= 10.0f; 14507 switch (metertype) 14508 { 14509 case MTYPE_ENERGY: 14510 case MTYPE_ENERGY_GENERATED: 14511 sprintf(szTmp, "%.3f", (TotalValue / divider)*1000.0f); //from kWh -> Watt 14512 break; 14513 case MTYPE_GAS: 14514 sprintf(szTmp, "%.2f", TotalValue / divider); 14515 break; 14516 case MTYPE_WATER: 14517 sprintf(szTmp, "%.3f", TotalValue / divider); 14518 break; 14519 case MTYPE_COUNTER: 14520 sprintf(szTmp, "%.1f", TotalValue); 14521 break; 14522 default: 14523 strcpy(szTmp, "0"); 14524 break; 14525 } 14526 root["result"][ii]["v"] = szTmp; 14527 ii++; 14528 } 14529 } 14530 } 14531 } 14532 else 14533 { 14534 root["status"] = "OK"; 14535 root["title"] = "Graph " + sensor + " " + srange; 14536 root["ValueQuantity"] = options["ValueQuantity"]; 14537 root["ValueUnits"] = options["ValueUnits"]; 14538 14539 int ii = 0; 14540 14541 bool bHaveFirstValue = false; 14542 bool bHaveFirstRealValue = false; 14543 unsigned long long ulFirstValue = 0; 14544 unsigned long long ulLastValue = 0; 14545 14546 std::string LastDateTime = ""; 14547 time_t lastTime = 0; 14548 14549 if (bIsManagedCounter) { 14550 result = m_sql.safe_query("SELECT Usage, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14551 bHaveFirstValue = true; 14552 bHaveFirstRealValue = true; 14553 } 14554 else { 14555 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14556 } 14557 14558 int method = 0; 14559 std::string sMethod = request::findValue(&req, "method"); 14560 if (sMethod.size() > 0) 14561 method = atoi(sMethod.c_str()); 14562 14563 if (!result.empty()) 14564 { 14565 for (const auto & itt : result) 14566 { 14567 std::vector<std::string> sd = itt; 14568 14569 if (method == 0) 14570 { 14571 //bars / hour 14572 14573 unsigned long long actValue = std::strtoull(sd[0].c_str(), nullptr, 10); 14574 14575 std::string actDateTimeHour = sd[1].substr(0, 13); 14576 if (actDateTimeHour != LastDateTime) 14577 { 14578 if (bHaveFirstValue) 14579 { 14580 struct tm ntime; 14581 time_t atime; 14582 if (actDateTimeHour.size() == 10) 14583 actDateTimeHour += " 00"; 14584 constructTime(atime, ntime, 14585 atoi(actDateTimeHour.substr(0, 4).c_str()), 14586 atoi(actDateTimeHour.substr(5, 2).c_str()), 14587 atoi(actDateTimeHour.substr(8, 2).c_str()), 14588 atoi(actDateTimeHour.substr(11, 2).c_str()) - 1, 14589 0, 0, -1); 14590 14591 char szTime[50]; 14592 sprintf(szTime, "%04d-%02d-%02d %02d:00", ntime.tm_year + 1900, ntime.tm_mon + 1, ntime.tm_mday, ntime.tm_hour); 14593 root["result"][ii]["d"] = szTime; 14594 14595 //float TotalValue = float(actValue - ulFirstValue); 14596 14597 //prevents graph from going crazy if the meter counter resets 14598 float TotalValue = (actValue >= ulFirstValue) ? float(actValue - ulFirstValue) : actValue; 14599 14600 //if (TotalValue != 0) 14601 { 14602 switch (metertype) 14603 { 14604 case MTYPE_ENERGY: 14605 case MTYPE_ENERGY_GENERATED: 14606 sprintf(szTmp, "%.3f", (TotalValue / divider)*1000.0f); //from kWh -> Watt 14607 break; 14608 case MTYPE_GAS: 14609 sprintf(szTmp, "%.3f", TotalValue / divider); 14610 break; 14611 case MTYPE_WATER: 14612 sprintf(szTmp, "%.3f", TotalValue / divider); 14613 break; 14614 case MTYPE_COUNTER: 14615 sprintf(szTmp, "%.1f", TotalValue); 14616 break; 14617 default: 14618 strcpy(szTmp, "0"); 14619 break; 14620 } 14621 root["result"][ii]["v"] = szTmp; 14622 ii++; 14623 } 14624 } 14625 if (!bIsManagedCounter) { 14626 ulFirstValue = actValue; 14627 } 14628 LastDateTime = actDateTimeHour; 14629 } 14630 14631 if (!bHaveFirstValue) 14632 { 14633 ulFirstValue = actValue; 14634 bHaveFirstValue = true; 14635 } 14636 ulLastValue = actValue; 14637 } 14638 else 14639 { 14640 //realtime graph 14641 unsigned long long actValue = std::strtoull(sd[0].c_str(), nullptr, 10); 14642 14643 std::string stime = sd[1]; 14644 struct tm ntime; 14645 time_t atime; 14646 ParseSQLdatetime(atime, ntime, stime, -1); 14647 if (bHaveFirstRealValue) 14648 { 14649 long long curValue = actValue - ulLastValue; 14650 14651 float tdiff = static_cast<float>(difftime(atime, lastTime)); 14652 if (tdiff == 0) 14653 tdiff = 1; 14654 float tlaps = 3600.0f / tdiff; 14655 curValue *= int(tlaps); 14656 14657 root["result"][ii]["d"] = sd[1].substr(0, 16); 14658 14659 float TotalValue = float(curValue); 14660 //if (TotalValue != 0) 14661 { 14662 switch (metertype) 14663 { 14664 case MTYPE_ENERGY: 14665 case MTYPE_ENERGY_GENERATED: 14666 sprintf(szTmp, "%.3f", (TotalValue / divider)*1000.0f); //from kWh -> Watt 14667 break; 14668 case MTYPE_GAS: 14669 sprintf(szTmp, "%.2f", TotalValue / divider); 14670 break; 14671 case MTYPE_WATER: 14672 sprintf(szTmp, "%.3f", TotalValue / divider); 14673 break; 14674 case MTYPE_COUNTER: 14675 sprintf(szTmp, "%.1f", TotalValue); 14676 break; 14677 default: 14678 strcpy(szTmp, "0"); 14679 break; 14680 } 14681 root["result"][ii]["v"] = szTmp; 14682 ii++; 14683 } 14684 14685 } 14686 else 14687 bHaveFirstRealValue = true; 14688 if (!bIsManagedCounter) { 14689 ulLastValue = actValue; 14690 } 14691 lastTime = atime; 14692 } 14693 } 14694 } 14695 if ((!bIsManagedCounter) && (bHaveFirstValue) && (method == 0)) 14696 { 14697 //add last value 14698 root["result"][ii]["d"] = LastDateTime + ":00"; 14699 14700 unsigned long long ulTotalValue = ulLastValue - ulFirstValue; 14701 14702 float TotalValue = float(ulTotalValue); 14703 14704 //if (TotalValue != 0) 14705 { 14706 switch (metertype) 14707 { 14708 case MTYPE_ENERGY: 14709 case MTYPE_ENERGY_GENERATED: 14710 sprintf(szTmp, "%.3f", (TotalValue / divider)*1000.0f); //from kWh -> Watt 14711 break; 14712 case MTYPE_GAS: 14713 sprintf(szTmp, "%.3f", TotalValue / divider); 14714 break; 14715 case MTYPE_WATER: 14716 sprintf(szTmp, "%.3f", TotalValue / divider); 14717 break; 14718 case MTYPE_COUNTER: 14719 sprintf(szTmp, "%.1f", TotalValue); 14720 break; 14721 default: 14722 strcpy(szTmp, "0"); 14723 break; 14724 } 14725 root["result"][ii]["v"] = szTmp; 14726 ii++; 14727 } 14728 } 14729 } 14730 } 14731 else if (sensor == "uv") { 14732 root["status"] = "OK"; 14733 root["title"] = "Graph " + sensor + " " + srange; 14734 14735 result = m_sql.safe_query("SELECT Level, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14736 if (!result.empty()) 14737 { 14738 int ii = 0; 14739 for (const auto & itt : result) 14740 { 14741 std::vector<std::string> sd = itt; 14742 14743 root["result"][ii]["d"] = sd[1].substr(0, 16); 14744 root["result"][ii]["uvi"] = sd[0]; 14745 ii++; 14746 } 14747 } 14748 } 14749 else if (sensor == "rain") { 14750 root["status"] = "OK"; 14751 root["title"] = "Graph " + sensor + " " + srange; 14752 14753 int LastHour = -1; 14754 float LastTotalPreviousHour = -1; 14755 14756 float LastValue = -1; 14757 std::string LastDate = ""; 14758 14759 result = m_sql.safe_query("SELECT Total, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14760 if (!result.empty()) 14761 { 14762 int ii = 0; 14763 for (const auto & itt : result) 14764 { 14765 std::vector<std::string> sd = itt; 14766 float ActTotal = static_cast<float>(atof(sd[0].c_str())); 14767 int Hour = atoi(sd[1].substr(11, 2).c_str()); 14768 if (Hour != LastHour) 14769 { 14770 if (LastHour != -1) 14771 { 14772 int NextCalculatedHour = (LastHour + 1) % 24; 14773 if (Hour != NextCalculatedHour) 14774 { 14775 //Looks like we have a GAP somewhere, finish the last hour 14776 root["result"][ii]["d"] = LastDate; 14777 double mmval = ActTotal - LastValue; 14778 mmval *= AddjMulti; 14779 sprintf(szTmp, "%.1f", mmval); 14780 root["result"][ii]["mm"] = szTmp; 14781 ii++; 14782 } 14783 else 14784 { 14785 root["result"][ii]["d"] = sd[1].substr(0, 16); 14786 double mmval = ActTotal - LastTotalPreviousHour; 14787 mmval *= AddjMulti; 14788 sprintf(szTmp, "%.1f", mmval); 14789 root["result"][ii]["mm"] = szTmp; 14790 ii++; 14791 } 14792 } 14793 LastHour = Hour; 14794 LastTotalPreviousHour = ActTotal; 14795 } 14796 LastValue = ActTotal; 14797 LastDate = sd[1]; 14798 } 14799 } 14800 } 14801 else if (sensor == "wind") { 14802 root["status"] = "OK"; 14803 root["title"] = "Graph " + sensor + " " + srange; 14804 14805 result = m_sql.safe_query("SELECT Direction, Speed, Gust, Date FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14806 if (!result.empty()) 14807 { 14808 int ii = 0; 14809 for (const auto & itt : result) 14810 { 14811 std::vector<std::string> sd = itt; 14812 14813 root["result"][ii]["d"] = sd[3].substr(0, 16); 14814 root["result"][ii]["di"] = sd[0]; 14815 14816 int intSpeed = atoi(sd[1].c_str()); 14817 int intGust = atoi(sd[2].c_str()); 14818 if (m_sql.m_windunit != WINDUNIT_Beaufort) 14819 { 14820 sprintf(szTmp, "%.1f", float(intSpeed) * m_sql.m_windscale); 14821 root["result"][ii]["sp"] = szTmp; 14822 sprintf(szTmp, "%.1f", float(intGust) * m_sql.m_windscale); 14823 root["result"][ii]["gu"] = szTmp; 14824 } 14825 else 14826 { 14827 float windspeedms = float(intSpeed)*0.1f; 14828 float windgustms = float(intGust)*0.1f; 14829 sprintf(szTmp, "%d", MStoBeaufort(windspeedms)); 14830 root["result"][ii]["sp"] = szTmp; 14831 sprintf(szTmp, "%d", MStoBeaufort(windgustms)); 14832 root["result"][ii]["gu"] = szTmp; 14833 } 14834 ii++; 14835 } 14836 } 14837 } 14838 else if (sensor == "winddir") { 14839 root["status"] = "OK"; 14840 root["title"] = "Graph " + sensor + " " + srange; 14841 14842 result = m_sql.safe_query("SELECT Direction, Speed, Gust FROM %s WHERE (DeviceRowID==%" PRIu64 ") ORDER BY Date ASC", dbasetable.c_str(), idx); 14843 if (!result.empty()) 14844 { 14845 std::map<int, int> _directions; 14846 int wdirtabletemp[17][8]; 14847 std::string szLegendLabels[7]; 14848 int ii = 0; 14849 14850 int totalvalues = 0; 14851 //init dir list 14852 int idir; 14853 for (idir = 0; idir < 360 + 1; idir++) 14854 _directions[idir] = 0; 14855 for (ii = 0; ii < 17; ii++) 14856 { 14857 for (int jj = 0; jj < 8; jj++) 14858 { 14859 wdirtabletemp[ii][jj] = 0; 14860 } 14861 } 14862 14863 if (m_sql.m_windunit == WINDUNIT_MS) 14864 { 14865 szLegendLabels[0] = "< 0.5 " + m_sql.m_windsign; 14866 szLegendLabels[1] = "0.5-2 " + m_sql.m_windsign; 14867 szLegendLabels[2] = "2-4 " + m_sql.m_windsign; 14868 szLegendLabels[3] = "4-6 " + m_sql.m_windsign; 14869 szLegendLabels[4] = "6-8 " + m_sql.m_windsign; 14870 szLegendLabels[5] = "8-10 " + m_sql.m_windsign; 14871 szLegendLabels[6] = "> 10" + m_sql.m_windsign; 14872 } 14873 else if (m_sql.m_windunit == WINDUNIT_KMH) 14874 { 14875 szLegendLabels[0] = "< 2 " + m_sql.m_windsign; 14876 szLegendLabels[1] = "2-4 " + m_sql.m_windsign; 14877 szLegendLabels[2] = "4-6 " + m_sql.m_windsign; 14878 szLegendLabels[3] = "6-10 " + m_sql.m_windsign; 14879 szLegendLabels[4] = "10-20 " + m_sql.m_windsign; 14880 szLegendLabels[5] = "20-36 " + m_sql.m_windsign; 14881 szLegendLabels[6] = "> 36" + m_sql.m_windsign; 14882 } 14883 else if (m_sql.m_windunit == WINDUNIT_MPH) 14884 { 14885 szLegendLabels[0] = "< 3 " + m_sql.m_windsign; 14886 szLegendLabels[1] = "3-7 " + m_sql.m_windsign; 14887 szLegendLabels[2] = "7-12 " + m_sql.m_windsign; 14888 szLegendLabels[3] = "12-18 " + m_sql.m_windsign; 14889 szLegendLabels[4] = "18-24 " + m_sql.m_windsign; 14890 szLegendLabels[5] = "24-46 " + m_sql.m_windsign; 14891 szLegendLabels[6] = "> 46" + m_sql.m_windsign; 14892 } 14893 else if (m_sql.m_windunit == WINDUNIT_Knots) 14894 { 14895 szLegendLabels[0] = "< 3 " + m_sql.m_windsign; 14896 szLegendLabels[1] = "3-7 " + m_sql.m_windsign; 14897 szLegendLabels[2] = "7-17 " + m_sql.m_windsign; 14898 szLegendLabels[3] = "17-27 " + m_sql.m_windsign; 14899 szLegendLabels[4] = "27-34 " + m_sql.m_windsign; 14900 szLegendLabels[5] = "34-41 " + m_sql.m_windsign; 14901 szLegendLabels[6] = "> 41" + m_sql.m_windsign; 14902 } 14903 else if (m_sql.m_windunit == WINDUNIT_Beaufort) 14904 { 14905 szLegendLabels[0] = "< 2 " + m_sql.m_windsign; 14906 szLegendLabels[1] = "2-4 " + m_sql.m_windsign; 14907 szLegendLabels[2] = "4-6 " + m_sql.m_windsign; 14908 szLegendLabels[3] = "6-8 " + m_sql.m_windsign; 14909 szLegendLabels[4] = "8-10 " + m_sql.m_windsign; 14910 szLegendLabels[5] = "10-12 " + m_sql.m_windsign; 14911 szLegendLabels[6] = "> 12" + m_sql.m_windsign; 14912 } 14913 else { 14914 //Todo ! 14915 szLegendLabels[0] = "< 0.5 " + m_sql.m_windsign; 14916 szLegendLabels[1] = "0.5-2 " + m_sql.m_windsign; 14917 szLegendLabels[2] = "2-4 " + m_sql.m_windsign; 14918 szLegendLabels[3] = "4-6 " + m_sql.m_windsign; 14919 szLegendLabels[4] = "6-8 " + m_sql.m_windsign; 14920 szLegendLabels[5] = "8-10 " + m_sql.m_windsign; 14921 szLegendLabels[6] = "> 10" + m_sql.m_windsign; 14922 } 14923 14924 14925 for (const auto & itt : result) 14926 { 14927 std::vector<std::string> sd = itt; 14928 float fdirection = static_cast<float>(atof(sd[0].c_str())); 14929 if (fdirection >= 360) 14930 fdirection = 0; 14931 int direction = int(fdirection); 14932 float speedOrg = static_cast<float>(atof(sd[1].c_str())); 14933 float gustOrg = static_cast<float>(atof(sd[2].c_str())); 14934 if ((gustOrg == 0) && (speedOrg != 0)) 14935 gustOrg = speedOrg; 14936 if (gustOrg == 0) 14937 continue; //no direction if wind is still 14938 //float speed = speedOrg * m_sql.m_windscale; 14939 float gust = gustOrg * m_sql.m_windscale; 14940 int bucket = int(fdirection / 22.5f); 14941 14942 int speedpos = 0; 14943 14944 if (m_sql.m_windunit == WINDUNIT_MS) 14945 { 14946 if (gust < 0.5f) speedpos = 0; 14947 else if (gust < 2.0f) speedpos = 1; 14948 else if (gust < 4.0f) speedpos = 2; 14949 else if (gust < 6.0f) speedpos = 3; 14950 else if (gust < 8.0f) speedpos = 4; 14951 else if (gust < 10.0f) speedpos = 5; 14952 else speedpos = 6; 14953 } 14954 else if (m_sql.m_windunit == WINDUNIT_KMH) 14955 { 14956 if (gust < 2.0f) speedpos = 0; 14957 else if (gust < 4.0f) speedpos = 1; 14958 else if (gust < 6.0f) speedpos = 2; 14959 else if (gust < 10.0f) speedpos = 3; 14960 else if (gust < 20.0f) speedpos = 4; 14961 else if (gust < 36.0f) speedpos = 5; 14962 else speedpos = 6; 14963 } 14964 else if (m_sql.m_windunit == WINDUNIT_MPH) 14965 { 14966 if (gust < 3.0f) speedpos = 0; 14967 else if (gust < 7.0f) speedpos = 1; 14968 else if (gust < 12.0f) speedpos = 2; 14969 else if (gust < 18.0f) speedpos = 3; 14970 else if (gust < 24.0f) speedpos = 4; 14971 else if (gust < 46.0f) speedpos = 5; 14972 else speedpos = 6; 14973 } 14974 else if (m_sql.m_windunit == WINDUNIT_Knots) 14975 { 14976 if (gust < 3.0f) speedpos = 0; 14977 else if (gust < 7.0f) speedpos = 1; 14978 else if (gust < 17.0f) speedpos = 2; 14979 else if (gust < 27.0f) speedpos = 3; 14980 else if (gust < 34.0f) speedpos = 4; 14981 else if (gust < 41.0f) speedpos = 5; 14982 else speedpos = 6; 14983 } 14984 else if (m_sql.m_windunit == WINDUNIT_Beaufort) 14985 { 14986 float gustms = gustOrg * 0.1f; 14987 int iBeaufort = MStoBeaufort(gustms); 14988 if (iBeaufort < 2) speedpos = 0; 14989 else if (iBeaufort < 4) speedpos = 1; 14990 else if (iBeaufort < 6) speedpos = 2; 14991 else if (iBeaufort < 8) speedpos = 3; 14992 else if (iBeaufort < 10) speedpos = 4; 14993 else if (iBeaufort < 12) speedpos = 5; 14994 else speedpos = 6; 14995 } 14996 else 14997 { 14998 //Still todo ! 14999 if (gust < 0.5f) speedpos = 0; 15000 else if (gust < 2.0f) speedpos = 1; 15001 else if (gust < 4.0f) speedpos = 2; 15002 else if (gust < 6.0f) speedpos = 3; 15003 else if (gust < 8.0f) speedpos = 4; 15004 else if (gust < 10.0f) speedpos = 5; 15005 else speedpos = 6; 15006 } 15007 wdirtabletemp[bucket][speedpos]++; 15008 _directions[direction]++; 15009 totalvalues++; 15010 } 15011 15012 for (int jj = 0; jj < 7; jj++) 15013 { 15014 root["result_speed"][jj]["label"] = szLegendLabels[jj]; 15015 15016 for (ii = 0; ii < 16; ii++) 15017 { 15018 float svalue = 0; 15019 if (totalvalues > 0) 15020 { 15021 svalue = (100.0f / totalvalues)*wdirtabletemp[ii][jj]; 15022 } 15023 sprintf(szTmp, "%.2f", svalue); 15024 root["result_speed"][jj]["sp"][ii] = szTmp; 15025 } 15026 } 15027 ii = 0; 15028 for (idir = 0; idir < 360 + 1; idir++) 15029 { 15030 if (_directions[idir] != 0) 15031 { 15032 root["result"][ii]["dig"] = idir; 15033 float percentage = 0; 15034 if (totalvalues > 0) 15035 { 15036 percentage = (float(100.0 / float(totalvalues))*float(_directions[idir])); 15037 } 15038 sprintf(szTmp, "%.2f", percentage); 15039 root["result"][ii]["div"] = szTmp; 15040 ii++; 15041 } 15042 } 15043 } 15044 } 15045 15046 }//day 15047 else if (srange == "week") 15048 { 15049 if (sensor == "rain") { 15050 root["status"] = "OK"; 15051 root["title"] = "Graph " + sensor + " " + srange; 15052 15053 char szDateStart[40]; 15054 char szDateEnd[40]; 15055 sprintf(szDateEnd, "%04d-%02d-%02d", tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday); 15056 15057 //Subtract one week 15058 time_t weekbefore; 15059 struct tm tm2; 15060 getNoon(weekbefore, tm2, tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday - 7); // We only want the date 15061 sprintf(szDateStart, "%04d-%02d-%02d", tm2.tm_year + 1900, tm2.tm_mon + 1, tm2.tm_mday); 15062 15063 result = m_sql.safe_query("SELECT Total, Rate, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 15064 int ii = 0; 15065 if (!result.empty()) 15066 { 15067 for (const auto & itt : result) 15068 { 15069 std::vector<std::string> sd = itt; 15070 15071 root["result"][ii]["d"] = sd[2].substr(0, 16); 15072 double mmval = atof(sd[0].c_str()); 15073 mmval *= AddjMulti; 15074 sprintf(szTmp, "%.1f", mmval); 15075 root["result"][ii]["mm"] = szTmp; 15076 ii++; 15077 } 15078 } 15079 //add today (have to calculate it) 15080 if (dSubType == sTypeRAINWU || dSubType == sTypeRAINByRate) 15081 { 15082 result = m_sql.safe_query( 15083 "SELECT Total, Total, Rate FROM Rain WHERE (DeviceRowID=%" PRIu64 " AND Date>='%q') ORDER BY ROWID DESC LIMIT 1", 15084 idx, szDateEnd); 15085 } 15086 else 15087 { 15088 result = m_sql.safe_query( 15089 "SELECT MIN(Total), MAX(Total), MAX(Rate) FROM Rain WHERE (DeviceRowID=%" PRIu64 " AND Date>='%q')", 15090 idx, szDateEnd); 15091 } 15092 if (!result.empty()) 15093 { 15094 std::vector<std::string> sd = result[0]; 15095 15096 float total_min = static_cast<float>(atof(sd[0].c_str())); 15097 float total_max = static_cast<float>(atof(sd[1].c_str())); 15098 //int rate = atoi(sd[2].c_str()); 15099 15100 double total_real = 0; 15101 if (dSubType == sTypeRAINWU || dSubType == sTypeRAINByRate) 15102 { 15103 total_real = total_max; 15104 } 15105 else 15106 { 15107 total_real = total_max - total_min; 15108 } 15109 total_real *= AddjMulti; 15110 sprintf(szTmp, "%.1f", total_real); 15111 root["result"][ii]["d"] = szDateEnd; 15112 root["result"][ii]["mm"] = szTmp; 15113 ii++; 15114 } 15115 } 15116 else if (sensor == "counter") 15117 { 15118 root["status"] = "OK"; 15119 root["title"] = "Graph " + sensor + " " + srange; 15120 root["ValueQuantity"] = options["ValueQuantity"]; 15121 root["ValueUnits"] = options["ValueUnits"]; 15122 15123 char szDateStart[40]; 15124 char szDateEnd[40]; 15125 sprintf(szDateEnd, "%04d-%02d-%02d", tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday); 15126 15127 //Subtract one week 15128 time_t weekbefore; 15129 struct tm tm2; 15130 getNoon(weekbefore, tm2, tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday - 7); // We only want the date 15131 sprintf(szDateStart, "%04d-%02d-%02d", tm2.tm_year + 1900, tm2.tm_mon + 1, tm2.tm_mday); 15132 15133 int ii = 0; 15134 if (dType == pTypeP1Power) 15135 { 15136 result = m_sql.safe_query("SELECT Value1,Value2,Value5,Value6,Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 15137 if (!result.empty()) 15138 { 15139 bool bHaveDeliverd = false; 15140 for (const auto & itt : result) 15141 { 15142 std::vector<std::string> sd = itt; 15143 root["result"][ii]["d"] = sd[4].substr(0, 16); 15144 std::string szValueUsage1 = sd[0]; 15145 std::string szValueDeliv1 = sd[1]; 15146 std::string szValueUsage2 = sd[2]; 15147 std::string szValueDeliv2 = sd[3]; 15148 15149 float fUsage1 = (float)(atof(szValueUsage1.c_str())); 15150 float fUsage2 = (float)(atof(szValueUsage2.c_str())); 15151 float fDeliv1 = (float)(atof(szValueDeliv1.c_str())); 15152 float fDeliv2 = (float)(atof(szValueDeliv2.c_str())); 15153 15154 fDeliv1 = (fDeliv1 < 10) ? 0 : fDeliv1; 15155 fDeliv2 = (fDeliv2 < 10) ? 0 : fDeliv2; 15156 15157 if ((fDeliv1 != 0) || (fDeliv2 != 0)) 15158 bHaveDeliverd = true; 15159 sprintf(szTmp, "%.3f", fUsage1 / divider); 15160 root["result"][ii]["v"] = szTmp; 15161 sprintf(szTmp, "%.3f", fUsage2 / divider); 15162 root["result"][ii]["v2"] = szTmp; 15163 sprintf(szTmp, "%.3f", fDeliv1 / divider); 15164 root["result"][ii]["r1"] = szTmp; 15165 sprintf(szTmp, "%.3f", fDeliv2 / divider); 15166 root["result"][ii]["r2"] = szTmp; 15167 ii++; 15168 } 15169 if (bHaveDeliverd) 15170 { 15171 root["delivered"] = true; 15172 } 15173 } 15174 } 15175 else 15176 { 15177 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 15178 if (!result.empty()) 15179 { 15180 for (const auto & itt : result) 15181 { 15182 std::vector<std::string> sd = itt; 15183 15184 root["result"][ii]["d"] = sd[1].substr(0, 16); 15185 std::string szValue = sd[0]; 15186 switch (metertype) 15187 { 15188 case MTYPE_ENERGY: 15189 case MTYPE_ENERGY_GENERATED: 15190 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15191 szValue = szTmp; 15192 break; 15193 case MTYPE_GAS: 15194 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15195 szValue = szTmp; 15196 break; 15197 case MTYPE_WATER: 15198 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15199 szValue = szTmp; 15200 break; 15201 case MTYPE_COUNTER: 15202 //value already set above! 15203 break; 15204 default: 15205 szValue = "0"; 15206 break; 15207 } 15208 root["result"][ii]["v"] = szValue; 15209 ii++; 15210 } 15211 } 15212 } 15213 //add today (have to calculate it) 15214 if (dType == pTypeP1Power) 15215 { 15216 result = m_sql.safe_query( 15217 "SELECT MIN(Value1), MAX(Value1), MIN(Value2), MAX(Value2),MIN(Value5), MAX(Value5), MIN(Value6), MAX(Value6) FROM MultiMeter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 15218 idx, szDateEnd); 15219 if (!result.empty()) 15220 { 15221 std::vector<std::string> sd = result[0]; 15222 15223 unsigned long long total_min_usage_1 = std::strtoull(sd[0].c_str(), nullptr, 10); 15224 unsigned long long total_max_usage_1 = std::strtoull(sd[1].c_str(), nullptr, 10); 15225 unsigned long long total_min_usage_2 = std::strtoull(sd[4].c_str(), nullptr, 10); 15226 unsigned long long total_max_usage_2 = std::strtoull(sd[5].c_str(), nullptr, 10); 15227 unsigned long long total_real_usage_1, total_real_usage_2; 15228 unsigned long long total_min_deliv_1 = std::strtoull(sd[2].c_str(), nullptr, 10); 15229 unsigned long long total_max_deliv_1 = std::strtoull(sd[3].c_str(), nullptr, 10); 15230 unsigned long long total_min_deliv_2 = std::strtoull(sd[6].c_str(), nullptr, 10); 15231 unsigned long long total_max_deliv_2 = std::strtoull(sd[7].c_str(), nullptr, 10); 15232 unsigned long long total_real_deliv_1, total_real_deliv_2; 15233 15234 bool bHaveDeliverd = false; 15235 15236 total_real_usage_1 = total_max_usage_1 - total_min_usage_1; 15237 total_real_usage_2 = total_max_usage_2 - total_min_usage_2; 15238 15239 total_real_deliv_1 = total_max_deliv_1 - total_min_deliv_1; 15240 total_real_deliv_2 = total_max_deliv_2 - total_min_deliv_2; 15241 if ((total_real_deliv_1 != 0) || (total_real_deliv_2 != 0)) 15242 bHaveDeliverd = true; 15243 15244 root["result"][ii]["d"] = szDateEnd; 15245 15246 sprintf(szTmp, "%llu", total_real_usage_1); 15247 std::string szValue = szTmp; 15248 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15249 root["result"][ii]["v"] = szTmp; 15250 sprintf(szTmp, "%llu", total_real_usage_2); 15251 szValue = szTmp; 15252 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15253 root["result"][ii]["v2"] = szTmp; 15254 15255 sprintf(szTmp, "%llu", total_real_deliv_1); 15256 szValue = szTmp; 15257 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15258 root["result"][ii]["r1"] = szTmp; 15259 sprintf(szTmp, "%llu", total_real_deliv_2); 15260 szValue = szTmp; 15261 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15262 root["result"][ii]["r2"] = szTmp; 15263 15264 ii++; 15265 if (bHaveDeliverd) 15266 { 15267 root["delivered"] = true; 15268 } 15269 } 15270 } 15271 else if (!bIsManagedCounter) 15272 { 15273 result = m_sql.safe_query("SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 15274 idx, szDateEnd); 15275 if (!result.empty()) 15276 { 15277 std::vector<std::string> sd = result[0]; 15278 15279 unsigned long long total_min = std::strtoull(sd[0].c_str(), nullptr, 10); 15280 unsigned long long total_max = std::strtoull(sd[1].c_str(), nullptr, 10); 15281 unsigned long long total_real; 15282 15283 total_real = total_max - total_min; 15284 sprintf(szTmp, "%llu", total_real); 15285 std::string szValue = szTmp; 15286 switch (metertype) 15287 { 15288 case MTYPE_ENERGY: 15289 case MTYPE_ENERGY_GENERATED: 15290 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15291 szValue = szTmp; 15292 break; 15293 case MTYPE_GAS: 15294 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15295 szValue = szTmp; 15296 break; 15297 case MTYPE_WATER: 15298 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 15299 szValue = szTmp; 15300 break; 15301 case MTYPE_COUNTER: 15302 //value already set above! 15303 break; 15304 default: 15305 szValue = "0"; 15306 break; 15307 } 15308 15309 root["result"][ii]["d"] = szDateEnd; 15310 root["result"][ii]["v"] = szValue; 15311 ii++; 15312 } 15313 } 15314 } 15315 }//week 15316 else if ((srange == "month") || (srange == "year")) 15317 { 15318 char szDateStart[40]; 15319 char szDateEnd[40]; 15320 char szDateStartPrev[40]; 15321 char szDateEndPrev[40]; 15322 15323 std::string sactmonth = request::findValue(&req, "actmonth"); 15324 std::string sactyear = request::findValue(&req, "actyear"); 15325 15326 int actMonth = atoi(sactmonth.c_str()); 15327 int actYear = atoi(sactyear.c_str()); 15328 15329 if ((sactmonth != "") && (sactyear != "")) 15330 { 15331 sprintf(szDateStart, "%04d-%02d-%02d", actYear, actMonth, 1); 15332 sprintf(szDateStartPrev, "%04d-%02d-%02d", actYear - 1, actMonth, 1); 15333 actMonth++; 15334 if (actMonth == 13) 15335 { 15336 actMonth = 1; 15337 actYear++; 15338 } 15339 sprintf(szDateEnd, "%04d-%02d-%02d", actYear, actMonth, 1); 15340 sprintf(szDateEndPrev, "%04d-%02d-%02d", actYear - 1, actMonth, 1); 15341 } 15342 else if (sactyear != "") 15343 { 15344 sprintf(szDateStart, "%04d-%02d-%02d", actYear, 1, 1); 15345 sprintf(szDateStartPrev, "%04d-%02d-%02d", actYear - 1, 1, 1); 15346 actYear++; 15347 sprintf(szDateEnd, "%04d-%02d-%02d", actYear, 1, 1); 15348 sprintf(szDateEndPrev, "%04d-%02d-%02d", actYear - 1, 1, 1); 15349 } 15350 else 15351 { 15352 sprintf(szDateEnd, "%04d-%02d-%02d", tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday); 15353 sprintf(szDateEndPrev, "%04d-%02d-%02d", tm1.tm_year + 1900 - 1, tm1.tm_mon + 1, tm1.tm_mday); 15354 15355 struct tm tm2; 15356 if (srange == "month") 15357 { 15358 //Subtract one month 15359 time_t monthbefore; 15360 getNoon(monthbefore, tm2, tm1.tm_year + 1900, tm1.tm_mon, tm1.tm_mday); 15361 } 15362 else 15363 { 15364 //Subtract one year 15365 time_t yearbefore; 15366 getNoon(yearbefore, tm2, tm1.tm_year + 1900 - 1, tm1.tm_mon + 1, tm1.tm_mday); 15367 } 15368 15369 sprintf(szDateStart, "%04d-%02d-%02d", tm2.tm_year + 1900, tm2.tm_mon + 1, tm2.tm_mday); 15370 sprintf(szDateStartPrev, "%04d-%02d-%02d", tm2.tm_year + 1900 - 1, tm2.tm_mon + 1, tm2.tm_mday); 15371 } 15372 15373 if (sensor == "temp") { 15374 root["status"] = "OK"; 15375 root["title"] = "Graph " + sensor + " " + srange; 15376 15377 //Actual Year 15378 result = m_sql.safe_query( 15379 "SELECT Temp_Min, Temp_Max, Chill_Min, Chill_Max," 15380 " Humidity, Barometer, Temp_Avg, Date, SetPoint_Min," 15381 " SetPoint_Max, SetPoint_Avg " 15382 "FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q'" 15383 " AND Date<='%q') ORDER BY Date ASC", 15384 dbasetable.c_str(), idx, szDateStart, szDateEnd); 15385 int ii = 0; 15386 if (!result.empty()) 15387 { 15388 for (const auto & itt : result) 15389 { 15390 std::vector<std::string> sd = itt; 15391 15392 root["result"][ii]["d"] = sd[7].substr(0, 16); 15393 15394 if ( 15395 (dType == pTypeRego6XXTemp) || (dType == pTypeTEMP) || (dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO) || (dType == pTypeTEMP_BARO) || (dType == pTypeWIND) || (dType == pTypeThermostat1) || (dType == pTypeRadiator1) || 15396 ((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorTemp)) || 15397 ((dType == pTypeUV) && (dSubType == sTypeUV3)) || 15398 ((dType == pTypeGeneral) && (dSubType == sTypeSystemTemp)) || 15399 ((dType == pTypeThermostat) && (dSubType == sTypeThermSetpoint)) || 15400 (dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater) || 15401 ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 15402 ) 15403 { 15404 bool bOK = true; 15405 if (dType == pTypeWIND) 15406 { 15407 bOK = ((dSubType != sTypeWINDNoTemp) && (dSubType != sTypeWINDNoTempNoChill)); 15408 } 15409 if (bOK) 15410 { 15411 double te = ConvertTemperature(atof(sd[1].c_str()), tempsign); 15412 double tm = ConvertTemperature(atof(sd[0].c_str()), tempsign); 15413 double ta = ConvertTemperature(atof(sd[6].c_str()), tempsign); 15414 root["result"][ii]["te"] = te; 15415 root["result"][ii]["tm"] = tm; 15416 root["result"][ii]["ta"] = ta; 15417 } 15418 } 15419 if ( 15420 ((dType == pTypeWIND) && (dSubType == sTypeWIND4)) || 15421 ((dType == pTypeWIND) && (dSubType == sTypeWINDNoTemp)) 15422 ) 15423 { 15424 double ch = ConvertTemperature(atof(sd[3].c_str()), tempsign); 15425 double cm = ConvertTemperature(atof(sd[2].c_str()), tempsign); 15426 root["result"][ii]["ch"] = ch; 15427 root["result"][ii]["cm"] = cm; 15428 } 15429 if ((dType == pTypeHUM) || (dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO)) 15430 { 15431 root["result"][ii]["hu"] = sd[4]; 15432 } 15433 if ( 15434 (dType == pTypeTEMP_HUM_BARO) || 15435 (dType == pTypeTEMP_BARO) || 15436 ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 15437 ) 15438 { 15439 if (dType == pTypeTEMP_HUM_BARO) 15440 { 15441 if (dSubType == sTypeTHBFloat) 15442 { 15443 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 15444 root["result"][ii]["ba"] = szTmp; 15445 } 15446 else 15447 root["result"][ii]["ba"] = sd[5]; 15448 } 15449 else if (dType == pTypeTEMP_BARO) 15450 { 15451 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 15452 root["result"][ii]["ba"] = szTmp; 15453 } 15454 else if ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 15455 { 15456 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 15457 root["result"][ii]["ba"] = szTmp; 15458 } 15459 } 15460 if ((dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater)) 15461 { 15462 double sm = ConvertTemperature(atof(sd[8].c_str()), tempsign); 15463 double sx = ConvertTemperature(atof(sd[9].c_str()), tempsign); 15464 double se = ConvertTemperature(atof(sd[10].c_str()), tempsign); 15465 root["result"][ii]["sm"] = sm; 15466 root["result"][ii]["se"] = se; 15467 root["result"][ii]["sx"] = sx; 15468 } 15469 ii++; 15470 } 15471 } 15472 //add today (have to calculate it) 15473 result = m_sql.safe_query( 15474 "SELECT MIN(Temperature), MAX(Temperature)," 15475 " MIN(Chill), MAX(Chill), AVG(Humidity)," 15476 " AVG(Barometer), AVG(Temperature), MIN(SetPoint)," 15477 " MAX(SetPoint), AVG(SetPoint) " 15478 "FROM Temperature WHERE (DeviceRowID==%" PRIu64 "" 15479 " AND Date>='%q')", 15480 idx, szDateEnd); 15481 if (!result.empty()) 15482 { 15483 std::vector<std::string> sd = result[0]; 15484 15485 root["result"][ii]["d"] = szDateEnd; 15486 if ( 15487 ((dType == pTypeRego6XXTemp) || (dType == pTypeTEMP) || (dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO) || (dType == pTypeTEMP_BARO) || (dType == pTypeWIND) || (dType == pTypeThermostat1) || (dType == pTypeRadiator1)) || 15488 ((dType == pTypeUV) && (dSubType == sTypeUV3)) || 15489 ((dType == pTypeWIND) && (dSubType == sTypeWIND4)) || 15490 (dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater) 15491 ) 15492 { 15493 double te = ConvertTemperature(atof(sd[1].c_str()), tempsign); 15494 double tm = ConvertTemperature(atof(sd[0].c_str()), tempsign); 15495 double ta = ConvertTemperature(atof(sd[6].c_str()), tempsign); 15496 15497 root["result"][ii]["te"] = te; 15498 root["result"][ii]["tm"] = tm; 15499 root["result"][ii]["ta"] = ta; 15500 } 15501 if ( 15502 ((dType == pTypeWIND) && (dSubType == sTypeWIND4)) || 15503 ((dType == pTypeWIND) && (dSubType == sTypeWINDNoTemp)) 15504 ) 15505 { 15506 double ch = ConvertTemperature(atof(sd[3].c_str()), tempsign); 15507 double cm = ConvertTemperature(atof(sd[2].c_str()), tempsign); 15508 root["result"][ii]["ch"] = ch; 15509 root["result"][ii]["cm"] = cm; 15510 } 15511 if ((dType == pTypeHUM) || (dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO)) 15512 { 15513 root["result"][ii]["hu"] = sd[4]; 15514 } 15515 if ( 15516 (dType == pTypeTEMP_HUM_BARO) || 15517 (dType == pTypeTEMP_BARO) || 15518 ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 15519 ) 15520 { 15521 if (dType == pTypeTEMP_HUM_BARO) 15522 { 15523 if (dSubType == sTypeTHBFloat) 15524 { 15525 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 15526 root["result"][ii]["ba"] = szTmp; 15527 } 15528 else 15529 root["result"][ii]["ba"] = sd[5]; 15530 } 15531 else if (dType == pTypeTEMP_BARO) 15532 { 15533 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 15534 root["result"][ii]["ba"] = szTmp; 15535 } 15536 else if ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 15537 { 15538 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 15539 root["result"][ii]["ba"] = szTmp; 15540 } 15541 } 15542 if ((dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater)) 15543 { 15544 double sx = ConvertTemperature(atof(sd[8].c_str()), tempsign); 15545 double sm = ConvertTemperature(atof(sd[7].c_str()), tempsign); 15546 double se = ConvertTemperature(atof(sd[9].c_str()), tempsign); 15547 root["result"][ii]["se"] = se; 15548 root["result"][ii]["sm"] = sm; 15549 root["result"][ii]["sx"] = sx; 15550 } 15551 ii++; 15552 } 15553 //Previous Year 15554 result = m_sql.safe_query( 15555 "SELECT Temp_Min, Temp_Max, Chill_Min, Chill_Max," 15556 " Humidity, Barometer, Temp_Avg, Date, SetPoint_Min," 15557 " SetPoint_Max, SetPoint_Avg " 15558 "FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q'" 15559 " AND Date<='%q') ORDER BY Date ASC", 15560 dbasetable.c_str(), idx, szDateStartPrev, szDateEndPrev); 15561 if (!result.empty()) 15562 { 15563 iPrev = 0; 15564 for (const auto & itt : result) 15565 { 15566 std::vector<std::string> sd = itt; 15567 15568 root["resultprev"][iPrev]["d"] = sd[7].substr(0, 16); 15569 15570 if ( 15571 (dType == pTypeRego6XXTemp) || (dType == pTypeTEMP) || (dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO) || (dType == pTypeTEMP_BARO) || (dType == pTypeWIND) || (dType == pTypeThermostat1) || (dType == pTypeRadiator1) || 15572 ((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorTemp)) || 15573 ((dType == pTypeUV) && (dSubType == sTypeUV3)) || 15574 ((dType == pTypeGeneral) && (dSubType == sTypeSystemTemp)) || 15575 ((dType == pTypeThermostat) && (dSubType == sTypeThermSetpoint)) || 15576 (dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater) 15577 ) 15578 { 15579 bool bOK = true; 15580 if (dType == pTypeWIND) 15581 { 15582 bOK = ((dSubType == sTypeWIND4) || (dSubType == sTypeWINDNoTemp)); 15583 } 15584 if (bOK) 15585 { 15586 double te = ConvertTemperature(atof(sd[1].c_str()), tempsign); 15587 double tm = ConvertTemperature(atof(sd[0].c_str()), tempsign); 15588 double ta = ConvertTemperature(atof(sd[6].c_str()), tempsign); 15589 root["resultprev"][iPrev]["te"] = te; 15590 root["resultprev"][iPrev]["tm"] = tm; 15591 root["resultprev"][iPrev]["ta"] = ta; 15592 } 15593 } 15594 if ( 15595 ((dType == pTypeWIND) && (dSubType == sTypeWIND4)) || 15596 ((dType == pTypeWIND) && (dSubType == sTypeWINDNoTemp)) 15597 ) 15598 { 15599 double ch = ConvertTemperature(atof(sd[3].c_str()), tempsign); 15600 double cm = ConvertTemperature(atof(sd[2].c_str()), tempsign); 15601 root["resultprev"][iPrev]["ch"] = ch; 15602 root["resultprev"][iPrev]["cm"] = cm; 15603 } 15604 if ((dType == pTypeHUM) || (dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO)) 15605 { 15606 root["resultprev"][iPrev]["hu"] = sd[4]; 15607 } 15608 if ( 15609 (dType == pTypeTEMP_HUM_BARO) || 15610 (dType == pTypeTEMP_BARO) || 15611 ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 15612 ) 15613 { 15614 if (dType == pTypeTEMP_HUM_BARO) 15615 { 15616 if (dSubType == sTypeTHBFloat) 15617 { 15618 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 15619 root["resultprev"][iPrev]["ba"] = szTmp; 15620 } 15621 else 15622 root["resultprev"][iPrev]["ba"] = sd[5]; 15623 } 15624 else if (dType == pTypeTEMP_BARO) 15625 { 15626 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 15627 root["resultprev"][iPrev]["ba"] = szTmp; 15628 } 15629 else if ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 15630 { 15631 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 15632 root["resultprev"][iPrev]["ba"] = szTmp; 15633 } 15634 } 15635 if ((dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater)) 15636 { 15637 double sx = ConvertTemperature(atof(sd[8].c_str()), tempsign); 15638 double sm = ConvertTemperature(atof(sd[7].c_str()), tempsign); 15639 double se = ConvertTemperature(atof(sd[9].c_str()), tempsign); 15640 root["resultprev"][iPrev]["se"] = se; 15641 root["resultprev"][iPrev]["sm"] = sm; 15642 root["resultprev"][iPrev]["sx"] = sx; 15643 } 15644 iPrev++; 15645 } 15646 } 15647 } 15648 else if (sensor == "Percentage") { 15649 root["status"] = "OK"; 15650 root["title"] = "Graph " + sensor + " " + srange; 15651 15652 result = m_sql.safe_query("SELECT Percentage_Min, Percentage_Max, Percentage_Avg, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 15653 int ii = 0; 15654 if (!result.empty()) 15655 { 15656 for (const auto & itt : result) 15657 { 15658 std::vector<std::string> sd = itt; 15659 15660 root["result"][ii]["d"] = sd[3].substr(0, 16); 15661 root["result"][ii]["v_min"] = sd[0]; 15662 root["result"][ii]["v_max"] = sd[1]; 15663 root["result"][ii]["v_avg"] = sd[2]; 15664 ii++; 15665 } 15666 } 15667 //add today (have to calculate it) 15668 result = m_sql.safe_query( 15669 "SELECT MIN(Percentage), MAX(Percentage), AVG(Percentage) FROM Percentage WHERE (DeviceRowID=%" PRIu64 " AND Date>='%q')", 15670 idx, szDateEnd); 15671 if (!result.empty()) 15672 { 15673 std::vector<std::string> sd = result[0]; 15674 root["result"][ii]["d"] = szDateEnd; 15675 root["result"][ii]["v_min"] = sd[0]; 15676 root["result"][ii]["v_max"] = sd[1]; 15677 root["result"][ii]["v_avg"] = sd[2]; 15678 ii++; 15679 } 15680 15681 } 15682 else if (sensor == "fan") { 15683 root["status"] = "OK"; 15684 root["title"] = "Graph " + sensor + " " + srange; 15685 15686 result = m_sql.safe_query("SELECT Speed_Min, Speed_Max, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 15687 int ii = 0; 15688 if (!result.empty()) 15689 { 15690 for (const auto & itt : result) 15691 { 15692 std::vector<std::string> sd = itt; 15693 15694 root["result"][ii]["d"] = sd[2].substr(0, 16); 15695 root["result"][ii]["v_max"] = sd[1]; 15696 root["result"][ii]["v_min"] = sd[0]; 15697 ii++; 15698 } 15699 } 15700 //add today (have to calculate it) 15701 result = m_sql.safe_query("SELECT MIN(Speed), MAX(Speed) FROM Fan WHERE (DeviceRowID=%" PRIu64 " AND Date>='%q')", 15702 idx, szDateEnd); 15703 if (!result.empty()) 15704 { 15705 std::vector<std::string> sd = result[0]; 15706 root["result"][ii]["d"] = szDateEnd; 15707 root["result"][ii]["v_max"] = sd[1]; 15708 root["result"][ii]["v_min"] = sd[0]; 15709 ii++; 15710 } 15711 15712 } 15713 else if (sensor == "uv") { 15714 root["status"] = "OK"; 15715 root["title"] = "Graph " + sensor + " " + srange; 15716 15717 result = m_sql.safe_query("SELECT Level, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 15718 int ii = 0; 15719 if (!result.empty()) 15720 { 15721 for (const auto & itt : result) 15722 { 15723 std::vector<std::string> sd = itt; 15724 15725 root["result"][ii]["d"] = sd[1].substr(0, 16); 15726 root["result"][ii]["uvi"] = sd[0]; 15727 ii++; 15728 } 15729 } 15730 //add today (have to calculate it) 15731 result = m_sql.safe_query( 15732 "SELECT MAX(Level) FROM UV WHERE (DeviceRowID=%" PRIu64 " AND Date>='%q')", 15733 idx, szDateEnd); 15734 if (!result.empty()) 15735 { 15736 std::vector<std::string> sd = result[0]; 15737 15738 root["result"][ii]["d"] = szDateEnd; 15739 root["result"][ii]["uvi"] = sd[0]; 15740 ii++; 15741 } 15742 //Previous Year 15743 result = m_sql.safe_query("SELECT Level, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStartPrev, szDateEndPrev); 15744 if (!result.empty()) 15745 { 15746 iPrev = 0; 15747 for (const auto & itt : result) 15748 { 15749 std::vector<std::string> sd = itt; 15750 15751 root["resultprev"][iPrev]["d"] = sd[1].substr(0, 16); 15752 root["resultprev"][iPrev]["uvi"] = sd[0]; 15753 iPrev++; 15754 } 15755 } 15756 } 15757 else if (sensor == "rain") { 15758 root["status"] = "OK"; 15759 root["title"] = "Graph " + sensor + " " + srange; 15760 15761 result = m_sql.safe_query("SELECT Total, Rate, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 15762 int ii = 0; 15763 if (!result.empty()) 15764 { 15765 for (const auto & itt : result) 15766 { 15767 std::vector<std::string> sd = itt; 15768 15769 root["result"][ii]["d"] = sd[2].substr(0, 16); 15770 double mmval = atof(sd[0].c_str()); 15771 mmval *= AddjMulti; 15772 sprintf(szTmp, "%.1f", mmval); 15773 root["result"][ii]["mm"] = szTmp; 15774 ii++; 15775 } 15776 } 15777 //add today (have to calculate it) 15778 if (dSubType == sTypeRAINWU || dSubType == sTypeRAINByRate) 15779 { 15780 result = m_sql.safe_query( 15781 "SELECT Total, Total, Rate FROM Rain WHERE (DeviceRowID=%" PRIu64 " AND Date>='%q') ORDER BY ROWID DESC LIMIT 1", 15782 idx, szDateEnd); 15783 } 15784 else 15785 { 15786 result = m_sql.safe_query( 15787 "SELECT MIN(Total), MAX(Total), MAX(Rate) FROM Rain WHERE (DeviceRowID=%" PRIu64 " AND Date>='%q')", 15788 idx, szDateEnd); 15789 } 15790 if (!result.empty()) 15791 { 15792 std::vector<std::string> sd = result[0]; 15793 15794 float total_min = static_cast<float>(atof(sd[0].c_str())); 15795 float total_max = static_cast<float>(atof(sd[1].c_str())); 15796 //int rate = atoi(sd[2].c_str()); 15797 15798 double total_real = 0; 15799 if (dSubType == sTypeRAINWU || dSubType == sTypeRAINByRate) 15800 { 15801 total_real = total_max; 15802 } 15803 else 15804 { 15805 total_real = total_max - total_min; 15806 } 15807 total_real *= AddjMulti; 15808 sprintf(szTmp, "%.1f", total_real); 15809 root["result"][ii]["d"] = szDateEnd; 15810 root["result"][ii]["mm"] = szTmp; 15811 ii++; 15812 } 15813 //Previous Year 15814 result = m_sql.safe_query( 15815 "SELECT Total, Rate, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStartPrev, szDateEndPrev); 15816 if (!result.empty()) 15817 { 15818 iPrev = 0; 15819 for (const auto & itt : result) 15820 { 15821 std::vector<std::string> sd = itt; 15822 15823 root["resultprev"][iPrev]["d"] = sd[2].substr(0, 16); 15824 double mmval = atof(sd[0].c_str()); 15825 mmval *= AddjMulti; 15826 sprintf(szTmp, "%.1f", mmval); 15827 root["resultprev"][iPrev]["mm"] = szTmp; 15828 iPrev++; 15829 } 15830 } 15831 } 15832 else if (sensor == "counter") { 15833 root["status"] = "OK"; 15834 root["title"] = "Graph " + sensor + " " + srange; 15835 root["ValueQuantity"] = options["ValueQuantity"]; 15836 root["ValueUnits"] = options["ValueUnits"]; 15837 15838 //int nValue = 0; 15839 std::string sValue = ""; 15840 15841 result = m_sql.safe_query("SELECT nValue, sValue FROM DeviceStatus WHERE (ID==%" PRIu64 ")", 15842 idx); 15843 if (!result.empty()) 15844 { 15845 std::vector<std::string> sd = result[0]; 15846 //nValue = atoi(sd[0].c_str()); 15847 sValue = sd[1]; 15848 } 15849 15850 int ii = 0; 15851 iPrev = 0; 15852 if (dType == pTypeP1Power) 15853 { 15854 //Actual Year 15855 result = m_sql.safe_query( 15856 "SELECT Value1,Value2,Value5,Value6, Date," 15857 " Counter1, Counter2, Counter3, Counter4 " 15858 "FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q'" 15859 " AND Date<='%q') ORDER BY Date ASC", 15860 dbasetable.c_str(), idx, szDateStart, szDateEnd); 15861 if (!result.empty()) 15862 { 15863 bool bHaveDeliverd = false; 15864 for (const auto & itt : result) 15865 { 15866 std::vector<std::string> sd = itt; 15867 15868 root["result"][ii]["d"] = sd[4].substr(0, 16); 15869 15870 double counter_1 = std::stod(sd[5]); 15871 double counter_2 = std::stod(sd[6]); 15872 double counter_3 = std::stod(sd[7]); 15873 double counter_4 = std::stod(sd[8]); 15874 15875 float fUsage_1 = std::stof(sd[0]); 15876 float fUsage_2 = std::stof(sd[2]); 15877 float fDeliv_1 = std::stof(sd[1]); 15878 float fDeliv_2 = std::stof(sd[3]); 15879 15880 fDeliv_1 = (fDeliv_1 < 10) ? 0 : fDeliv_1; 15881 fDeliv_2 = (fDeliv_2 < 10) ? 0 : fDeliv_2; 15882 15883 if ((fDeliv_1 != 0) || (fDeliv_2 != 0)) 15884 bHaveDeliverd = true; 15885 sprintf(szTmp, "%.3f", fUsage_1 / divider); 15886 root["result"][ii]["v"] = szTmp; 15887 sprintf(szTmp, "%.3f", fUsage_2 / divider); 15888 root["result"][ii]["v2"] = szTmp; 15889 sprintf(szTmp, "%.3f", fDeliv_1 / divider); 15890 root["result"][ii]["r1"] = szTmp; 15891 sprintf(szTmp, "%.3f", fDeliv_2 / divider); 15892 root["result"][ii]["r2"] = szTmp; 15893 15894 if (counter_1 != 0) 15895 { 15896 sprintf(szTmp, "%.3f", (counter_1 - fUsage_1) / divider); 15897 } 15898 else 15899 { 15900 strcpy(szTmp, "0"); 15901 } 15902 root["result"][ii]["c1"] = szTmp; 15903 15904 if (counter_2 != 0) 15905 { 15906 sprintf(szTmp, "%.3f", (counter_2 - fDeliv_1) / divider); 15907 } 15908 else 15909 { 15910 strcpy(szTmp, "0"); 15911 } 15912 root["result"][ii]["c2"] = szTmp; 15913 15914 if (counter_3 != 0) 15915 { 15916 sprintf(szTmp, "%.3f", (counter_3 - fUsage_2) / divider); 15917 } 15918 else 15919 { 15920 strcpy(szTmp, "0"); 15921 } 15922 root["result"][ii]["c3"] = szTmp; 15923 15924 if (counter_4 != 0) 15925 { 15926 sprintf(szTmp, "%.3f", (counter_4 - fDeliv_2) / divider); 15927 } 15928 else 15929 { 15930 strcpy(szTmp, "0"); 15931 } 15932 root["result"][ii]["c4"] = szTmp; 15933 15934 ii++; 15935 } 15936 if (bHaveDeliverd) 15937 { 15938 root["delivered"] = true; 15939 } 15940 } 15941 //Previous Year 15942 result = m_sql.safe_query( 15943 "SELECT Value1,Value2,Value5,Value6, Date " 15944 "FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", 15945 dbasetable.c_str(), idx, szDateStartPrev, szDateEndPrev); 15946 if (!result.empty()) 15947 { 15948 bool bHaveDeliverd = false; 15949 iPrev = 0; 15950 for (const auto & itt : result) 15951 { 15952 std::vector<std::string> sd = itt; 15953 15954 root["resultprev"][iPrev]["d"] = sd[4].substr(0, 16); 15955 15956 float fUsage_1 = std::stof(sd[0]); 15957 float fUsage_2 = std::stof(sd[2]); 15958 float fDeliv_1 = std::stof(sd[1]); 15959 float fDeliv_2 = std::stof(sd[3]); 15960 15961 if ((fDeliv_1 != 0) || (fDeliv_2 != 0)) 15962 bHaveDeliverd = true; 15963 sprintf(szTmp, "%.3f", fUsage_1 / divider); 15964 root["resultprev"][iPrev]["v"] = szTmp; 15965 sprintf(szTmp, "%.3f", fUsage_2 / divider); 15966 root["resultprev"][iPrev]["v2"] = szTmp; 15967 sprintf(szTmp, "%.3f", fDeliv_1 / divider); 15968 root["resultprev"][iPrev]["r1"] = szTmp; 15969 sprintf(szTmp, "%.3f", fDeliv_2 / divider); 15970 root["resultprev"][iPrev]["r2"] = szTmp; 15971 iPrev++; 15972 } 15973 if (bHaveDeliverd) 15974 { 15975 root["delivered"] = true; 15976 } 15977 } 15978 } 15979 else if (dType == pTypeAirQuality) 15980 {//month/year 15981 root["status"] = "OK"; 15982 root["title"] = "Graph " + sensor + " " + srange; 15983 15984 result = m_sql.safe_query("SELECT Value1,Value2,Value3,Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 15985 if (!result.empty()) 15986 { 15987 for (const auto & itt : result) 15988 { 15989 std::vector<std::string> sd = itt; 15990 15991 root["result"][ii]["d"] = sd[3].substr(0, 16); 15992 root["result"][ii]["co2_min"] = sd[0]; 15993 root["result"][ii]["co2_max"] = sd[1]; 15994 root["result"][ii]["co2_avg"] = sd[2]; 15995 ii++; 15996 } 15997 } 15998 result = m_sql.safe_query("SELECT Value2,Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStartPrev, szDateEndPrev); 15999 if (!result.empty()) 16000 { 16001 iPrev = 0; 16002 for (const auto & itt : result) 16003 { 16004 std::vector<std::string> sd = itt; 16005 16006 root["resultprev"][iPrev]["d"] = sd[1].substr(0, 16); 16007 root["resultprev"][iPrev]["co2_max"] = sd[0]; 16008 iPrev++; 16009 } 16010 } 16011 } 16012 else if ( 16013 ((dType == pTypeGeneral) && ((dSubType == sTypeSoilMoisture) || (dSubType == sTypeLeafWetness))) || 16014 ((dType == pTypeRFXSensor) && ((dSubType == sTypeRFXSensorAD) || (dSubType == sTypeRFXSensorVolt))) 16015 ) 16016 {//month/year 16017 root["status"] = "OK"; 16018 root["title"] = "Graph " + sensor + " " + srange; 16019 16020 result = m_sql.safe_query("SELECT Value1,Value2, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 16021 if (!result.empty()) 16022 { 16023 for (const auto & itt : result) 16024 { 16025 std::vector<std::string> sd = itt; 16026 16027 root["result"][ii]["d"] = sd[2].substr(0, 16); 16028 root["result"][ii]["v_min"] = sd[0]; 16029 root["result"][ii]["v_max"] = sd[1]; 16030 ii++; 16031 } 16032 } 16033 } 16034 else if ( 16035 ((dType == pTypeGeneral) && (dSubType == sTypeVisibility)) || 16036 ((dType == pTypeGeneral) && (dSubType == sTypeDistance)) || 16037 ((dType == pTypeGeneral) && (dSubType == sTypeSolarRadiation)) || 16038 ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) || 16039 ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) || 16040 ((dType == pTypeGeneral) && (dSubType == sTypePressure)) || 16041 ((dType == pTypeGeneral) && (dSubType == sTypeSoundLevel)) 16042 ) 16043 {//month/year 16044 root["status"] = "OK"; 16045 root["title"] = "Graph " + sensor + " " + srange; 16046 16047 float vdiv = 10.0f; 16048 if ( 16049 ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) || 16050 ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) 16051 ) 16052 { 16053 vdiv = 1000.0f; 16054 } 16055 16056 result = m_sql.safe_query("SELECT Value1,Value2,Value3,Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 16057 if (!result.empty()) 16058 { 16059 for (const auto & itt : result) 16060 { 16061 std::vector<std::string> sd = itt; 16062 16063 float fValue1 = float(atof(sd[0].c_str())) / vdiv; 16064 float fValue2 = float(atof(sd[1].c_str())) / vdiv; 16065 float fValue3 = float(atof(sd[2].c_str())) / vdiv; 16066 root["result"][ii]["d"] = sd[3].substr(0, 16); 16067 16068 if (metertype == 1) 16069 { 16070 fValue1 *= 0.6214f; 16071 fValue2 *= 0.6214f; 16072 } 16073 if ( 16074 ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) || 16075 ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) 16076 ) 16077 { 16078 sprintf(szTmp, "%.3f", fValue1); 16079 root["result"][ii]["v_min"] = szTmp; 16080 sprintf(szTmp, "%.3f", fValue2); 16081 root["result"][ii]["v_max"] = szTmp; 16082 if (fValue3 != 0) 16083 { 16084 sprintf(szTmp, "%.3f", fValue3); 16085 root["result"][ii]["v_avg"] = szTmp; 16086 } 16087 } 16088 else 16089 { 16090 sprintf(szTmp, "%.1f", fValue1); 16091 root["result"][ii]["v_min"] = szTmp; 16092 sprintf(szTmp, "%.1f", fValue2); 16093 root["result"][ii]["v_max"] = szTmp; 16094 if (fValue3 != 0) 16095 { 16096 sprintf(szTmp, "%.1f", fValue3); 16097 root["result"][ii]["v_avg"] = szTmp; 16098 } 16099 } 16100 ii++; 16101 } 16102 } 16103 } 16104 else if (dType == pTypeLux) 16105 {//month/year 16106 root["status"] = "OK"; 16107 root["title"] = "Graph " + sensor + " " + srange; 16108 16109 result = m_sql.safe_query("SELECT Value1,Value2,Value3, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 16110 if (!result.empty()) 16111 { 16112 for (const auto & itt : result) 16113 { 16114 std::vector<std::string> sd = itt; 16115 16116 root["result"][ii]["d"] = sd[3].substr(0, 16); 16117 root["result"][ii]["lux_min"] = sd[0]; 16118 root["result"][ii]["lux_max"] = sd[1]; 16119 root["result"][ii]["lux_avg"] = sd[2]; 16120 ii++; 16121 } 16122 } 16123 } 16124 else if (dType == pTypeWEIGHT) 16125 {//month/year 16126 root["status"] = "OK"; 16127 root["title"] = "Graph " + sensor + " " + srange; 16128 16129 result = m_sql.safe_query( 16130 "SELECT Value1,Value2, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 16131 if (!result.empty()) 16132 { 16133 for (const auto & itt : result) 16134 { 16135 std::vector<std::string> sd = itt; 16136 16137 root["result"][ii]["d"] = sd[2].substr(0, 16); 16138 sprintf(szTmp, "%.1f", m_sql.m_weightscale * atof(sd[0].c_str()) / 10.0f); 16139 root["result"][ii]["v_min"] = szTmp; 16140 sprintf(szTmp, "%.1f", m_sql.m_weightscale * atof(sd[1].c_str()) / 10.0f); 16141 root["result"][ii]["v_max"] = szTmp; 16142 ii++; 16143 } 16144 } 16145 } 16146 else if (dType == pTypeUsage) 16147 {//month/year 16148 root["status"] = "OK"; 16149 root["title"] = "Graph " + sensor + " " + srange; 16150 16151 result = m_sql.safe_query( 16152 "SELECT Value1,Value2, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 16153 if (!result.empty()) 16154 { 16155 for (const auto & itt : result) 16156 { 16157 std::vector<std::string> sd = itt; 16158 16159 root["result"][ii]["d"] = sd[2].substr(0, 16); 16160 root["result"][ii]["u_min"] = atof(sd[0].c_str()) / 10.0f; 16161 root["result"][ii]["u_max"] = atof(sd[1].c_str()) / 10.0f; 16162 ii++; 16163 } 16164 } 16165 } 16166 else if (dType == pTypeCURRENT) 16167 { 16168 result = m_sql.safe_query("SELECT Value1,Value2,Value3,Value4,Value5,Value6, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 16169 if (!result.empty()) 16170 { 16171 //CM113 16172 int displaytype = 0; 16173 int voltage = 230; 16174 m_sql.GetPreferencesVar("CM113DisplayType", displaytype); 16175 m_sql.GetPreferencesVar("ElectricVoltage", voltage); 16176 16177 root["displaytype"] = displaytype; 16178 16179 bool bHaveL1 = false; 16180 bool bHaveL2 = false; 16181 bool bHaveL3 = false; 16182 for (const auto & itt : result) 16183 { 16184 std::vector<std::string> sd = itt; 16185 16186 root["result"][ii]["d"] = sd[6].substr(0, 16); 16187 16188 float fval1 = static_cast<float>(atof(sd[0].c_str()) / 10.0f); 16189 float fval2 = static_cast<float>(atof(sd[1].c_str()) / 10.0f); 16190 float fval3 = static_cast<float>(atof(sd[2].c_str()) / 10.0f); 16191 float fval4 = static_cast<float>(atof(sd[3].c_str()) / 10.0f); 16192 float fval5 = static_cast<float>(atof(sd[4].c_str()) / 10.0f); 16193 float fval6 = static_cast<float>(atof(sd[5].c_str()) / 10.0f); 16194 16195 if ((fval1 != 0) || (fval2 != 0)) 16196 bHaveL1 = true; 16197 if ((fval3 != 0) || (fval4 != 0)) 16198 bHaveL2 = true; 16199 if ((fval5 != 0) || (fval6 != 0)) 16200 bHaveL3 = true; 16201 16202 if (displaytype == 0) 16203 { 16204 sprintf(szTmp, "%.1f", fval1); 16205 root["result"][ii]["v1"] = szTmp; 16206 sprintf(szTmp, "%.1f", fval2); 16207 root["result"][ii]["v2"] = szTmp; 16208 sprintf(szTmp, "%.1f", fval3); 16209 root["result"][ii]["v3"] = szTmp; 16210 sprintf(szTmp, "%.1f", fval4); 16211 root["result"][ii]["v4"] = szTmp; 16212 sprintf(szTmp, "%.1f", fval5); 16213 root["result"][ii]["v5"] = szTmp; 16214 sprintf(szTmp, "%.1f", fval6); 16215 root["result"][ii]["v6"] = szTmp; 16216 } 16217 else 16218 { 16219 sprintf(szTmp, "%d", int(fval1*voltage)); 16220 root["result"][ii]["v1"] = szTmp; 16221 sprintf(szTmp, "%d", int(fval2*voltage)); 16222 root["result"][ii]["v2"] = szTmp; 16223 sprintf(szTmp, "%d", int(fval3*voltage)); 16224 root["result"][ii]["v3"] = szTmp; 16225 sprintf(szTmp, "%d", int(fval4*voltage)); 16226 root["result"][ii]["v4"] = szTmp; 16227 sprintf(szTmp, "%d", int(fval5*voltage)); 16228 root["result"][ii]["v5"] = szTmp; 16229 sprintf(szTmp, "%d", int(fval6*voltage)); 16230 root["result"][ii]["v6"] = szTmp; 16231 } 16232 16233 ii++; 16234 } 16235 if ( 16236 (!bHaveL1) && 16237 (!bHaveL2) && 16238 (!bHaveL3) 16239 ) { 16240 root["haveL1"] = true; //show at least something 16241 } 16242 else { 16243 if (bHaveL1) 16244 root["haveL1"] = true; 16245 if (bHaveL2) 16246 root["haveL2"] = true; 16247 if (bHaveL3) 16248 root["haveL3"] = true; 16249 } 16250 } 16251 } 16252 else if (dType == pTypeCURRENTENERGY) 16253 { 16254 result = m_sql.safe_query("SELECT Value1,Value2,Value3,Value4,Value5,Value6, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 16255 if (!result.empty()) 16256 { 16257 //CM180i 16258 int displaytype = 0; 16259 int voltage = 230; 16260 m_sql.GetPreferencesVar("CM113DisplayType", displaytype); 16261 m_sql.GetPreferencesVar("ElectricVoltage", voltage); 16262 16263 root["displaytype"] = displaytype; 16264 16265 bool bHaveL1 = false; 16266 bool bHaveL2 = false; 16267 bool bHaveL3 = false; 16268 for (const auto & itt : result) 16269 { 16270 std::vector<std::string> sd = itt; 16271 16272 root["result"][ii]["d"] = sd[6].substr(0, 16); 16273 16274 float fval1 = static_cast<float>(atof(sd[0].c_str()) / 10.0f); 16275 float fval2 = static_cast<float>(atof(sd[1].c_str()) / 10.0f); 16276 float fval3 = static_cast<float>(atof(sd[2].c_str()) / 10.0f); 16277 float fval4 = static_cast<float>(atof(sd[3].c_str()) / 10.0f); 16278 float fval5 = static_cast<float>(atof(sd[4].c_str()) / 10.0f); 16279 float fval6 = static_cast<float>(atof(sd[5].c_str()) / 10.0f); 16280 16281 if ((fval1 != 0) || (fval2 != 0)) 16282 bHaveL1 = true; 16283 if ((fval3 != 0) || (fval4 != 0)) 16284 bHaveL2 = true; 16285 if ((fval5 != 0) || (fval6 != 0)) 16286 bHaveL3 = true; 16287 16288 if (displaytype == 0) 16289 { 16290 sprintf(szTmp, "%.1f", fval1); 16291 root["result"][ii]["v1"] = szTmp; 16292 sprintf(szTmp, "%.1f", fval2); 16293 root["result"][ii]["v2"] = szTmp; 16294 sprintf(szTmp, "%.1f", fval3); 16295 root["result"][ii]["v3"] = szTmp; 16296 sprintf(szTmp, "%.1f", fval4); 16297 root["result"][ii]["v4"] = szTmp; 16298 sprintf(szTmp, "%.1f", fval5); 16299 root["result"][ii]["v5"] = szTmp; 16300 sprintf(szTmp, "%.1f", fval6); 16301 root["result"][ii]["v6"] = szTmp; 16302 } 16303 else 16304 { 16305 sprintf(szTmp, "%d", int(fval1*voltage)); 16306 root["result"][ii]["v1"] = szTmp; 16307 sprintf(szTmp, "%d", int(fval2*voltage)); 16308 root["result"][ii]["v2"] = szTmp; 16309 sprintf(szTmp, "%d", int(fval3*voltage)); 16310 root["result"][ii]["v3"] = szTmp; 16311 sprintf(szTmp, "%d", int(fval4*voltage)); 16312 root["result"][ii]["v4"] = szTmp; 16313 sprintf(szTmp, "%d", int(fval5*voltage)); 16314 root["result"][ii]["v5"] = szTmp; 16315 sprintf(szTmp, "%d", int(fval6*voltage)); 16316 root["result"][ii]["v6"] = szTmp; 16317 } 16318 16319 ii++; 16320 } 16321 if ( 16322 (!bHaveL1) && 16323 (!bHaveL2) && 16324 (!bHaveL3) 16325 ) { 16326 root["haveL1"] = true; //show at least something 16327 } 16328 else { 16329 if (bHaveL1) 16330 root["haveL1"] = true; 16331 if (bHaveL2) 16332 root["haveL2"] = true; 16333 if (bHaveL3) 16334 root["haveL3"] = true; 16335 } 16336 } 16337 } 16338 else 16339 { 16340 if (dType == pTypeP1Gas) 16341 { 16342 //Add last counter value 16343 sprintf(szTmp, "%.3f", atof(sValue.c_str()) / 1000.0); 16344 root["counter"] = szTmp; 16345 } 16346 else if (dType == pTypeENERGY) 16347 { 16348 size_t spos = sValue.find(";"); 16349 if (spos != std::string::npos) 16350 { 16351 float fvalue = static_cast<float>(atof(sValue.substr(spos + 1).c_str())); 16352 sprintf(szTmp, "%.3f", fvalue / (divider / 100.0f)); 16353 root["counter"] = szTmp; 16354 } 16355 } 16356 else if ((dType == pTypeGeneral) && (dSubType == sTypeKwh)) 16357 { 16358 size_t spos = sValue.find(";"); 16359 if (spos != std::string::npos) 16360 { 16361 float fvalue = static_cast<float>(atof(sValue.substr(spos + 1).c_str())); 16362 sprintf(szTmp, "%.3f", fvalue / divider); 16363 root["counter"] = szTmp; 16364 } 16365 } 16366 else if (dType == pTypeRFXMeter) 16367 { 16368 //Add last counter value 16369 float fvalue = static_cast<float>(atof(sValue.c_str())); 16370 switch (metertype) 16371 { 16372 case MTYPE_ENERGY: 16373 case MTYPE_ENERGY_GENERATED: 16374 sprintf(szTmp, "%.3f", AddjValue + (fvalue / divider)); 16375 break; 16376 case MTYPE_GAS: 16377 sprintf(szTmp, "%.2f", AddjValue + (fvalue / divider)); 16378 break; 16379 case MTYPE_WATER: 16380 sprintf(szTmp, "%.3f", AddjValue + (fvalue / divider)); 16381 break; 16382 default: 16383 strcpy(szTmp, ""); 16384 break; 16385 } 16386 root["counter"] = szTmp; 16387 } 16388 else if (dType == pTypeYouLess) 16389 { 16390 std::vector<std::string> results; 16391 StringSplit(sValue, ";", results); 16392 if (results.size() == 2) 16393 { 16394 //Add last counter value 16395 float fvalue = static_cast<float>(atof(results[0].c_str())); 16396 switch (metertype) 16397 { 16398 case MTYPE_ENERGY: 16399 case MTYPE_ENERGY_GENERATED: 16400 sprintf(szTmp, "%.3f", fvalue / divider); 16401 break; 16402 case MTYPE_GAS: 16403 sprintf(szTmp, "%.2f", fvalue / divider); 16404 break; 16405 case MTYPE_WATER: 16406 sprintf(szTmp, "%.3f", fvalue / divider); 16407 break; 16408 default: 16409 strcpy(szTmp, ""); 16410 break; 16411 } 16412 root["counter"] = szTmp; 16413 } 16414 } 16415 else if (!bIsManagedCounter) 16416 { 16417 //Add last counter value 16418 sprintf(szTmp, "%d", atoi(sValue.c_str())); 16419 root["counter"] = szTmp; 16420 } 16421 else 16422 { 16423 root["counter"] = "0"; 16424 } 16425 //Actual Year 16426 result = m_sql.safe_query("SELECT Value, Date, Counter FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart, szDateEnd); 16427 if (!result.empty()) 16428 { 16429 for (const auto & itt : result) 16430 { 16431 std::vector<std::string> sd = itt; 16432 16433 root["result"][ii]["d"] = sd[1].substr(0, 16); 16434 16435 std::string szValue = sd[0]; 16436 16437 double fcounter = atof(sd[2].c_str()); 16438 16439 switch (metertype) 16440 { 16441 case MTYPE_ENERGY: 16442 case MTYPE_ENERGY_GENERATED: 16443 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 16444 root["result"][ii]["v"] = szTmp; 16445 if (fcounter != 0) 16446 sprintf(szTmp, "%.3f", AddjValue + ((fcounter - atof(szValue.c_str())) / divider)); 16447 else 16448 strcpy(szTmp, "0"); 16449 root["result"][ii]["c"] = szTmp; 16450 break; 16451 case MTYPE_GAS: 16452 sprintf(szTmp, "%.2f", atof(szValue.c_str()) / divider); 16453 root["result"][ii]["v"] = szTmp; 16454 if (fcounter != 0) 16455 sprintf(szTmp, "%.2f", AddjValue + ((fcounter - atof(szValue.c_str())) / divider)); 16456 else 16457 strcpy(szTmp, "0"); 16458 root["result"][ii]["c"] = szTmp; 16459 break; 16460 case MTYPE_WATER: 16461 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 16462 root["result"][ii]["v"] = szTmp; 16463 if (fcounter != 0) 16464 sprintf(szTmp, "%.3f", AddjValue + ((fcounter - atof(szValue.c_str())) / divider)); 16465 else 16466 strcpy(szTmp, "0"); 16467 root["result"][ii]["c"] = szTmp; 16468 break; 16469 case MTYPE_COUNTER: 16470 sprintf(szTmp, "%.0f", atof(szValue.c_str())); 16471 root["result"][ii]["v"] = szTmp; 16472 if (fcounter != 0) 16473 sprintf(szTmp, "%.0f", AddjValue + ((fcounter - atof(szValue.c_str())))); 16474 else 16475 strcpy(szTmp, "0"); 16476 root["result"][ii]["c"] = szTmp; 16477 break; 16478 } 16479 ii++; 16480 } 16481 } 16482 //Past Year 16483 result = m_sql.safe_query("SELECT Value, Date, Counter FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStartPrev, szDateEndPrev); 16484 if (!result.empty()) 16485 { 16486 iPrev = 0; 16487 for (const auto & itt : result) 16488 { 16489 std::vector<std::string> sd = itt; 16490 16491 root["resultprev"][iPrev]["d"] = sd[1].substr(0, 16); 16492 16493 std::string szValue = sd[0]; 16494 switch (metertype) 16495 { 16496 case MTYPE_ENERGY: 16497 case MTYPE_ENERGY_GENERATED: 16498 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 16499 root["resultprev"][iPrev]["v"] = szTmp; 16500 break; 16501 case MTYPE_GAS: 16502 sprintf(szTmp, "%.2f", atof(szValue.c_str()) / divider); 16503 root["resultprev"][iPrev]["v"] = szTmp; 16504 break; 16505 case MTYPE_WATER: 16506 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 16507 root["resultprev"][iPrev]["v"] = szTmp; 16508 break; 16509 case MTYPE_COUNTER: 16510 sprintf(szTmp, "%.0f", atof(szValue.c_str())); 16511 root["resultprev"][iPrev]["v"] = szTmp; 16512 break; 16513 } 16514 iPrev++; 16515 } 16516 } 16517 } 16518 //add today (have to calculate it) 16519 16520 if ((sactmonth != "") || (sactyear != "")) 16521 { 16522 struct tm loctime; 16523 time_t now = mytime(NULL); 16524 localtime_r(&now, &loctime); 16525 if ((sactmonth != "") && (sactyear != "")) 16526 { 16527 bool bIsThisMonth = (atoi(sactyear.c_str()) == loctime.tm_year + 1900) && (atoi(sactmonth.c_str()) == loctime.tm_mon + 1); 16528 if (bIsThisMonth) 16529 { 16530 sprintf(szDateEnd, "%04d-%02d-%02d", loctime.tm_year + 1900, loctime.tm_mon + 1, loctime.tm_mday); 16531 } 16532 } 16533 else if (sactyear != "") 16534 { 16535 bool bIsThisYear = (atoi(sactyear.c_str()) == loctime.tm_year + 1900); 16536 if (bIsThisYear) 16537 { 16538 sprintf(szDateEnd, "%04d-%02d-%02d", loctime.tm_year + 1900, loctime.tm_mon + 1, loctime.tm_mday); 16539 } 16540 16541 } 16542 } 16543 16544 if (dType == pTypeP1Power) 16545 { 16546 result = m_sql.safe_query( 16547 "SELECT MIN(Value1), MAX(Value1), MIN(Value2)," 16548 " MAX(Value2), MIN(Value5), MAX(Value5)," 16549 " MIN(Value6), MAX(Value6) " 16550 "FROM MultiMeter WHERE (DeviceRowID=%" PRIu64 "" 16551 " AND Date>='%q')", 16552 idx, szDateEnd); 16553 bool bHaveDeliverd = false; 16554 if (!result.empty()) 16555 { 16556 std::vector<std::string> sd = result[0]; 16557 unsigned long long total_min_usage_1 = std::strtoull(sd[0].c_str(), nullptr, 10); 16558 unsigned long long total_max_usage_1 = std::strtoull(sd[1].c_str(), nullptr, 10); 16559 unsigned long long total_min_usage_2 = std::strtoull(sd[4].c_str(), nullptr, 10); 16560 unsigned long long total_max_usage_2 = std::strtoull(sd[5].c_str(), nullptr, 10); 16561 unsigned long long total_real_usage_1, total_real_usage_2; 16562 unsigned long long total_min_deliv_1 = std::strtoull(sd[2].c_str(), nullptr, 10); 16563 unsigned long long total_max_deliv_1 = std::strtoull(sd[3].c_str(), nullptr, 10); 16564 unsigned long long total_min_deliv_2 = std::strtoull(sd[6].c_str(), nullptr, 10); 16565 unsigned long long total_max_deliv_2 = std::strtoull(sd[7].c_str(), nullptr, 10); 16566 unsigned long long total_real_deliv_1, total_real_deliv_2; 16567 16568 total_real_usage_1 = total_max_usage_1 - total_min_usage_1; 16569 total_real_usage_2 = total_max_usage_2 - total_min_usage_2; 16570 16571 total_real_deliv_1 = total_max_deliv_1 - total_min_deliv_1; 16572 total_real_deliv_2 = total_max_deliv_2 - total_min_deliv_2; 16573 16574 if ((total_real_deliv_1 != 0) || (total_real_deliv_2 != 0)) 16575 bHaveDeliverd = true; 16576 16577 root["result"][ii]["d"] = szDateEnd; 16578 16579 sprintf(szTmp, "%.3f", (float)(total_real_usage_1 / divider)); 16580 root["result"][ii]["v"] = szTmp; 16581 sprintf(szTmp, "%.3f", (float)(total_real_usage_2 / divider)); 16582 root["result"][ii]["v2"] = szTmp; 16583 16584 sprintf(szTmp, "%.3f", (float)(total_real_deliv_1 / divider)); 16585 root["result"][ii]["r1"] = szTmp; 16586 sprintf(szTmp, "%.3f", (float)(total_real_deliv_2 / divider)); 16587 root["result"][ii]["r2"] = szTmp; 16588 16589 sprintf(szTmp, "%.3f", (float)(total_min_usage_1 / divider)); 16590 root["result"][ii]["c1"] = szTmp; 16591 sprintf(szTmp, "%.3f", (float)(total_min_usage_2 / divider)); 16592 root["result"][ii]["c3"] = szTmp; 16593 16594 if (total_max_deliv_2 != 0) 16595 { 16596 sprintf(szTmp, "%.3f", (float)(total_min_deliv_1 / divider)); 16597 root["result"][ii]["c2"] = szTmp; 16598 sprintf(szTmp, "%.3f", (float)(total_min_deliv_2 / divider)); 16599 root["result"][ii]["c4"] = szTmp; 16600 } 16601 else 16602 { 16603 strcpy(szTmp, "0"); 16604 root["result"][ii]["c2"] = szTmp; 16605 root["result"][ii]["c4"] = szTmp; 16606 } 16607 16608 ii++; 16609 } 16610 if (bHaveDeliverd) 16611 { 16612 root["delivered"] = true; 16613 } 16614 } 16615 else if (dType == pTypeAirQuality) 16616 { 16617 result = m_sql.safe_query( 16618 "SELECT MIN(Value), MAX(Value), AVG(Value) FROM Meter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 16619 idx, szDateEnd); 16620 if (!result.empty()) 16621 { 16622 root["result"][ii]["d"] = szDateEnd; 16623 root["result"][ii]["co2_min"] = result[0][0]; 16624 root["result"][ii]["co2_max"] = result[0][1]; 16625 root["result"][ii]["co2_avg"] = result[0][2]; 16626 ii++; 16627 } 16628 } 16629 else if ( 16630 ((dType == pTypeGeneral) && ((dSubType == sTypeSoilMoisture) || (dSubType == sTypeLeafWetness))) || 16631 ((dType == pTypeRFXSensor) && ((dSubType == sTypeRFXSensorAD) || (dSubType == sTypeRFXSensorVolt))) 16632 ) 16633 { 16634 result = m_sql.safe_query( 16635 "SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 16636 idx, szDateEnd); 16637 if (!result.empty()) 16638 { 16639 root["result"][ii]["d"] = szDateEnd; 16640 root["result"][ii]["v_min"] = result[0][0]; 16641 root["result"][ii]["v_max"] = result[0][1]; 16642 ii++; 16643 } 16644 } 16645 else if ( 16646 ((dType == pTypeGeneral) && (dSubType == sTypeVisibility)) || 16647 ((dType == pTypeGeneral) && (dSubType == sTypeDistance)) || 16648 ((dType == pTypeGeneral) && (dSubType == sTypeSolarRadiation)) || 16649 ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) || 16650 ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) || 16651 ((dType == pTypeGeneral) && (dSubType == sTypePressure)) || 16652 ((dType == pTypeGeneral) && (dSubType == sTypeSoundLevel)) 16653 ) 16654 { 16655 float vdiv = 10.0f; 16656 if ( 16657 ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) || 16658 ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) 16659 ) 16660 { 16661 vdiv = 1000.0f; 16662 } 16663 16664 result = m_sql.safe_query( 16665 "SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 16666 idx, szDateEnd); 16667 if (!result.empty()) 16668 { 16669 root["result"][ii]["d"] = szDateEnd; 16670 float fValue1 = float(atof(result[0][0].c_str())) / vdiv; 16671 float fValue2 = float(atof(result[0][1].c_str())) / vdiv; 16672 if (metertype == 1) 16673 { 16674 fValue1 *= 0.6214f; 16675 fValue2 *= 0.6214f; 16676 } 16677 16678 if ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) 16679 sprintf(szTmp, "%.3f", fValue1); 16680 else if ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) 16681 sprintf(szTmp, "%.3f", fValue1); 16682 else 16683 sprintf(szTmp, "%.1f", fValue1); 16684 root["result"][ii]["v_min"] = szTmp; 16685 if ((dType == pTypeGeneral) && (dSubType == sTypeVoltage)) 16686 sprintf(szTmp, "%.3f", fValue2); 16687 else if ((dType == pTypeGeneral) && (dSubType == sTypeCurrent)) 16688 sprintf(szTmp, "%.3f", fValue2); 16689 else 16690 sprintf(szTmp, "%.1f", fValue2); 16691 root["result"][ii]["v_max"] = szTmp; 16692 ii++; 16693 } 16694 } 16695 else if (dType == pTypeLux) 16696 { 16697 result = m_sql.safe_query( 16698 "SELECT MIN(Value), MAX(Value), AVG(Value) FROM Meter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 16699 idx, szDateEnd); 16700 if (!result.empty()) 16701 { 16702 root["result"][ii]["d"] = szDateEnd; 16703 root["result"][ii]["lux_min"] = result[0][0]; 16704 root["result"][ii]["lux_max"] = result[0][1]; 16705 root["result"][ii]["lux_avg"] = result[0][2]; 16706 ii++; 16707 } 16708 } 16709 else if (dType == pTypeWEIGHT) 16710 { 16711 result = m_sql.safe_query( 16712 "SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 16713 idx, szDateEnd); 16714 if (!result.empty()) 16715 { 16716 root["result"][ii]["d"] = szDateEnd; 16717 sprintf(szTmp, "%.1f", m_sql.m_weightscale* atof(result[0][0].c_str()) / 10.0f); 16718 root["result"][ii]["v_min"] = szTmp; 16719 sprintf(szTmp, "%.1f", m_sql.m_weightscale * atof(result[0][1].c_str()) / 10.0f); 16720 root["result"][ii]["v_max"] = szTmp; 16721 ii++; 16722 } 16723 } 16724 else if (dType == pTypeUsage) 16725 { 16726 result = m_sql.safe_query( 16727 "SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID=%" PRIu64 " AND Date>='%q')", 16728 idx, szDateEnd); 16729 if (!result.empty()) 16730 { 16731 root["result"][ii]["d"] = szDateEnd; 16732 root["result"][ii]["u_min"] = atof(result[0][0].c_str()) / 10.0f; 16733 root["result"][ii]["u_max"] = atof(result[0][1].c_str()) / 10.0f; 16734 ii++; 16735 } 16736 } 16737 else if (!bIsManagedCounter) 16738 { 16739 result = m_sql.safe_query( 16740 "SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 16741 idx, szDateEnd); 16742 if (!result.empty()) 16743 { 16744 std::vector<std::string> sd = result[0]; 16745 unsigned long long total_min = std::strtoull(sd[0].c_str(), nullptr, 10); 16746 unsigned long long total_max = std::strtoull(sd[1].c_str(), nullptr, 10); 16747 unsigned long long total_real; 16748 16749 total_real = total_max - total_min; 16750 sprintf(szTmp, "%llu", total_real); 16751 16752 root["result"][ii]["d"] = szDateEnd; 16753 16754 std::string szValue = szTmp; 16755 switch (metertype) 16756 { 16757 case MTYPE_ENERGY: 16758 case MTYPE_ENERGY_GENERATED: 16759 { 16760 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 16761 root["result"][ii]["v"] = szTmp; 16762 16763 std::vector<std::string> mresults; 16764 StringSplit(sValue, ";", mresults); 16765 if (mresults.size() == 2) 16766 { 16767 sValue = mresults[1]; 16768 } 16769 if (dType == pTypeENERGY) 16770 sprintf(szTmp, "%.3f", AddjValue + (((atof(sValue.c_str())*100.0f) - atof(szValue.c_str())) / divider)); 16771 else 16772 sprintf(szTmp, "%.3f", AddjValue + ((atof(sValue.c_str()) - atof(szValue.c_str())) / divider)); 16773 root["result"][ii]["c"] = szTmp; 16774 } 16775 break; 16776 case MTYPE_GAS: 16777 sprintf(szTmp, "%.2f", atof(szValue.c_str()) / divider); 16778 root["result"][ii]["v"] = szTmp; 16779 sprintf(szTmp, "%.2f", AddjValue + ((atof(sValue.c_str()) - atof(szValue.c_str())) / divider)); 16780 root["result"][ii]["c"] = szTmp; 16781 break; 16782 case MTYPE_WATER: 16783 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 16784 root["result"][ii]["v"] = szTmp; 16785 sprintf(szTmp, "%.3f", AddjValue + ((atof(sValue.c_str()) - atof(szValue.c_str())) / divider)); 16786 root["result"][ii]["c"] = szTmp; 16787 break; 16788 case MTYPE_COUNTER: 16789 sprintf(szTmp, "%.0f", atof(szValue.c_str())); 16790 root["result"][ii]["v"] = szTmp; 16791 sprintf(szTmp, "%.0f", AddjValue + ((atof(sValue.c_str()) - atof(szValue.c_str())))); 16792 root["result"][ii]["c"] = szTmp; 16793 break; 16794 } 16795 ii++; 16796 } 16797 } 16798 } 16799 else if (sensor == "wind") { 16800 root["status"] = "OK"; 16801 root["title"] = "Graph " + sensor + " " + srange; 16802 16803 int ii = 0; 16804 16805 result = m_sql.safe_query( 16806 "SELECT Direction, Speed_Min, Speed_Max, Gust_Min," 16807 " Gust_Max, Date " 16808 "FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q'" 16809 " AND Date<='%q') ORDER BY Date ASC", 16810 dbasetable.c_str(), idx, szDateStart, szDateEnd); 16811 if (!result.empty()) 16812 { 16813 for (const auto & itt : result) 16814 { 16815 std::vector<std::string> sd = itt; 16816 16817 root["result"][ii]["d"] = sd[5].substr(0, 16); 16818 root["result"][ii]["di"] = sd[0]; 16819 16820 int intSpeed = atoi(sd[2].c_str()); 16821 int intGust = atoi(sd[4].c_str()); 16822 if (m_sql.m_windunit != WINDUNIT_Beaufort) 16823 { 16824 sprintf(szTmp, "%.1f", float(intSpeed) * m_sql.m_windscale); 16825 root["result"][ii]["sp"] = szTmp; 16826 sprintf(szTmp, "%.1f", float(intGust) * m_sql.m_windscale); 16827 root["result"][ii]["gu"] = szTmp; 16828 } 16829 else 16830 { 16831 float windspeedms = float(intSpeed)*0.1f; 16832 float windgustms = float(intGust)*0.1f; 16833 sprintf(szTmp, "%d", MStoBeaufort(windspeedms)); 16834 root["result"][ii]["sp"] = szTmp; 16835 sprintf(szTmp, "%d", MStoBeaufort(windgustms)); 16836 root["result"][ii]["gu"] = szTmp; 16837 } 16838 ii++; 16839 } 16840 } 16841 //add today (have to calculate it) 16842 result = m_sql.safe_query( 16843 "SELECT AVG(Direction), MIN(Speed), MAX(Speed)," 16844 " MIN(Gust), MAX(Gust) " 16845 "FROM Wind WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q') ORDER BY Date ASC", 16846 idx, szDateEnd); 16847 if (!result.empty()) 16848 { 16849 std::vector<std::string> sd = result[0]; 16850 16851 root["result"][ii]["d"] = szDateEnd; 16852 root["result"][ii]["di"] = sd[0]; 16853 16854 int intSpeed = atoi(sd[2].c_str()); 16855 int intGust = atoi(sd[4].c_str()); 16856 if (m_sql.m_windunit != WINDUNIT_Beaufort) 16857 { 16858 sprintf(szTmp, "%.1f", float(intSpeed) * m_sql.m_windscale); 16859 root["result"][ii]["sp"] = szTmp; 16860 sprintf(szTmp, "%.1f", float(intGust) * m_sql.m_windscale); 16861 root["result"][ii]["gu"] = szTmp; 16862 } 16863 else 16864 { 16865 float windspeedms = float(intSpeed)*0.1f; 16866 float windgustms = float(intGust)*0.1f; 16867 sprintf(szTmp, "%d", MStoBeaufort(windspeedms)); 16868 root["result"][ii]["sp"] = szTmp; 16869 sprintf(szTmp, "%d", MStoBeaufort(windgustms)); 16870 root["result"][ii]["gu"] = szTmp; 16871 } 16872 ii++; 16873 } 16874 //Previous Year 16875 result = m_sql.safe_query( 16876 "SELECT Direction, Speed_Min, Speed_Max, Gust_Min," 16877 " Gust_Max, Date " 16878 "FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q'" 16879 " AND Date<='%q') ORDER BY Date ASC", 16880 dbasetable.c_str(), idx, szDateStartPrev, szDateEndPrev); 16881 if (!result.empty()) 16882 { 16883 iPrev = 0; 16884 for (const auto & itt : result) 16885 { 16886 std::vector<std::string> sd = itt; 16887 16888 root["resultprev"][iPrev]["d"] = sd[5].substr(0, 16); 16889 root["resultprev"][iPrev]["di"] = sd[0]; 16890 16891 int intSpeed = atoi(sd[2].c_str()); 16892 int intGust = atoi(sd[4].c_str()); 16893 if (m_sql.m_windunit != WINDUNIT_Beaufort) 16894 { 16895 sprintf(szTmp, "%.1f", float(intSpeed) * m_sql.m_windscale); 16896 root["resultprev"][iPrev]["sp"] = szTmp; 16897 sprintf(szTmp, "%.1f", float(intGust) * m_sql.m_windscale); 16898 root["resultprev"][iPrev]["gu"] = szTmp; 16899 } 16900 else 16901 { 16902 float windspeedms = float(intSpeed)*0.1f; 16903 float windgustms = float(intGust)*0.1f; 16904 sprintf(szTmp, "%d", MStoBeaufort(windspeedms)); 16905 root["resultprev"][iPrev]["sp"] = szTmp; 16906 sprintf(szTmp, "%d", MStoBeaufort(windgustms)); 16907 root["resultprev"][iPrev]["gu"] = szTmp; 16908 } 16909 iPrev++; 16910 } 16911 } 16912 } 16913 }//month or year 16914 else if ((srange.substr(0, 1) == "2") && (srange.substr(10, 1) == "T") && (srange.substr(11, 1) == "2")) // custom range 2013-01-01T2013-12-31 16915 { 16916 std::string szDateStart = srange.substr(0, 10); 16917 std::string szDateEnd = srange.substr(11, 10); 16918 std::string sgraphtype = request::findValue(&req, "graphtype"); 16919 std::string sgraphTemp = request::findValue(&req, "graphTemp"); 16920 std::string sgraphChill = request::findValue(&req, "graphChill"); 16921 std::string sgraphHum = request::findValue(&req, "graphHum"); 16922 std::string sgraphBaro = request::findValue(&req, "graphBaro"); 16923 std::string sgraphDew = request::findValue(&req, "graphDew"); 16924 std::string sgraphSet = request::findValue(&req, "graphSet"); 16925 16926 if (sensor == "temp") { 16927 root["status"] = "OK"; 16928 root["title"] = "Graph " + sensor + " " + srange; 16929 16930 bool sendTemp = false; 16931 bool sendChill = false; 16932 bool sendHum = false; 16933 bool sendBaro = false; 16934 bool sendDew = false; 16935 bool sendSet = false; 16936 16937 if ((sgraphTemp == "true") && 16938 ((dType == pTypeRego6XXTemp) || (dType == pTypeTEMP) || (dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO) || (dType == pTypeTEMP_BARO) || (dType == pTypeWIND) || (dType == pTypeThermostat1) || (dType == pTypeRadiator1) || 16939 ((dType == pTypeUV) && (dSubType == sTypeUV3)) || 16940 ((dType == pTypeWIND) && (dSubType == sTypeWIND4)) || 16941 ((dType == pTypeRFXSensor) && (dSubType == sTypeRFXSensorTemp)) || 16942 ((dType == pTypeThermostat) && (dSubType == sTypeThermSetpoint)) || 16943 (dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater) 16944 ) 16945 ) 16946 { 16947 sendTemp = true; 16948 } 16949 if ((sgraphSet == "true") && 16950 ((dType == pTypeEvohomeZone) || (dType == pTypeEvohomeWater))) //FIXME cheat for water setpoint is just on or off 16951 { 16952 sendSet = true; 16953 } 16954 if ((sgraphChill == "true") && 16955 (((dType == pTypeWIND) && (dSubType == sTypeWIND4)) || 16956 ((dType == pTypeWIND) && (dSubType == sTypeWINDNoTemp))) 16957 ) 16958 { 16959 sendChill = true; 16960 } 16961 if ((sgraphHum == "true") && 16962 ((dType == pTypeHUM) || (dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO)) 16963 ) 16964 { 16965 sendHum = true; 16966 } 16967 if ((sgraphBaro == "true") && ( 16968 (dType == pTypeTEMP_HUM_BARO) || 16969 (dType == pTypeTEMP_BARO) || 16970 ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 16971 )) 16972 { 16973 sendBaro = true; 16974 } 16975 if ((sgraphDew == "true") && ((dType == pTypeTEMP_HUM) || (dType == pTypeTEMP_HUM_BARO))) 16976 { 16977 sendDew = true; 16978 } 16979 16980 if (sgraphtype == "1") 16981 { 16982 // Need to get all values of the end date so 23:59:59 is appended to the date string 16983 result = m_sql.safe_query( 16984 "SELECT Temperature, Chill, Humidity, Barometer," 16985 " Date, DewPoint, SetPoint " 16986 "FROM Temperature WHERE (DeviceRowID==%" PRIu64 "" 16987 " AND Date>='%q' AND Date<='%q 23:59:59') ORDER BY Date ASC", 16988 idx, szDateStart.c_str(), szDateEnd.c_str()); 16989 int ii = 0; 16990 if (!result.empty()) 16991 { 16992 for (const auto & itt : result) 16993 { 16994 std::vector<std::string> sd = itt; 16995 16996 root["result"][ii]["d"] = sd[4];//.substr(0,16); 16997 if (sendTemp) 16998 { 16999 double te = ConvertTemperature(atof(sd[0].c_str()), tempsign); 17000 double tm = ConvertTemperature(atof(sd[0].c_str()), tempsign); 17001 root["result"][ii]["te"] = te; 17002 root["result"][ii]["tm"] = tm; 17003 } 17004 if (sendChill) 17005 { 17006 double ch = ConvertTemperature(atof(sd[1].c_str()), tempsign); 17007 double cm = ConvertTemperature(atof(sd[1].c_str()), tempsign); 17008 root["result"][ii]["ch"] = ch; 17009 root["result"][ii]["cm"] = cm; 17010 } 17011 if (sendHum) 17012 { 17013 root["result"][ii]["hu"] = sd[2]; 17014 } 17015 if (sendBaro) 17016 { 17017 if (dType == pTypeTEMP_HUM_BARO) 17018 { 17019 if (dSubType == sTypeTHBFloat) 17020 { 17021 sprintf(szTmp, "%.1f", atof(sd[3].c_str()) / 10.0f); 17022 root["result"][ii]["ba"] = szTmp; 17023 } 17024 else 17025 root["result"][ii]["ba"] = sd[3]; 17026 } 17027 else if (dType == pTypeTEMP_BARO) 17028 { 17029 sprintf(szTmp, "%.1f", atof(sd[3].c_str()) / 10.0f); 17030 root["result"][ii]["ba"] = szTmp; 17031 } 17032 else if ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 17033 { 17034 sprintf(szTmp, "%.1f", atof(sd[3].c_str()) / 10.0f); 17035 root["result"][ii]["ba"] = szTmp; 17036 } 17037 } 17038 if (sendDew) 17039 { 17040 double dp = ConvertTemperature(atof(sd[5].c_str()), tempsign); 17041 root["result"][ii]["dp"] = dp; 17042 } 17043 if (sendSet) 17044 { 17045 double se = ConvertTemperature(atof(sd[6].c_str()), tempsign); 17046 root["result"][ii]["se"] = se; 17047 } 17048 ii++; 17049 } 17050 } 17051 } 17052 else 17053 { 17054 result = m_sql.safe_query( 17055 "SELECT Temp_Min, Temp_Max, Chill_Min, Chill_Max," 17056 " Humidity, Barometer, Date, DewPoint, Temp_Avg," 17057 " SetPoint_Min, SetPoint_Max, SetPoint_Avg " 17058 "FROM Temperature_Calendar " 17059 "WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q'" 17060 " AND Date<='%q') ORDER BY Date ASC", 17061 idx, szDateStart.c_str(), szDateEnd.c_str()); 17062 int ii = 0; 17063 if (!result.empty()) 17064 { 17065 for (const auto & itt : result) 17066 { 17067 std::vector<std::string> sd = itt; 17068 17069 root["result"][ii]["d"] = sd[6].substr(0, 16); 17070 if (sendTemp) 17071 { 17072 double te = ConvertTemperature(atof(sd[1].c_str()), tempsign); 17073 double tm = ConvertTemperature(atof(sd[0].c_str()), tempsign); 17074 double ta = ConvertTemperature(atof(sd[8].c_str()), tempsign); 17075 17076 root["result"][ii]["te"] = te; 17077 root["result"][ii]["tm"] = tm; 17078 root["result"][ii]["ta"] = ta; 17079 } 17080 if (sendChill) 17081 { 17082 double ch = ConvertTemperature(atof(sd[3].c_str()), tempsign); 17083 double cm = ConvertTemperature(atof(sd[2].c_str()), tempsign); 17084 17085 root["result"][ii]["ch"] = ch; 17086 root["result"][ii]["cm"] = cm; 17087 } 17088 if (sendHum) 17089 { 17090 root["result"][ii]["hu"] = sd[4]; 17091 } 17092 if (sendBaro) 17093 { 17094 if (dType == pTypeTEMP_HUM_BARO) 17095 { 17096 if (dSubType == sTypeTHBFloat) 17097 { 17098 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 17099 root["result"][ii]["ba"] = szTmp; 17100 } 17101 else 17102 root["result"][ii]["ba"] = sd[5]; 17103 } 17104 else if (dType == pTypeTEMP_BARO) 17105 { 17106 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 17107 root["result"][ii]["ba"] = szTmp; 17108 } 17109 else if ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 17110 { 17111 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 17112 root["result"][ii]["ba"] = szTmp; 17113 } 17114 } 17115 if (sendDew) 17116 { 17117 double dp = ConvertTemperature(atof(sd[7].c_str()), tempsign); 17118 root["result"][ii]["dp"] = dp; 17119 } 17120 if (sendSet) 17121 { 17122 double sm = ConvertTemperature(atof(sd[9].c_str()), tempsign); 17123 double sx = ConvertTemperature(atof(sd[10].c_str()), tempsign); 17124 double se = ConvertTemperature(atof(sd[11].c_str()), tempsign); 17125 root["result"][ii]["sm"] = sm; 17126 root["result"][ii]["se"] = se; 17127 root["result"][ii]["sx"] = sx; 17128 char szTmp[1024]; 17129 sprintf(szTmp, "%.1f %.1f %.1f", sm, se, sx); 17130 _log.Log(LOG_STATUS, "%s", szTmp); 17131 17132 } 17133 ii++; 17134 } 17135 } 17136 17137 //add today (have to calculate it) 17138 result = m_sql.safe_query( 17139 "SELECT MIN(Temperature), MAX(Temperature)," 17140 " MIN(Chill), MAX(Chill), AVG(Humidity)," 17141 " AVG(Barometer), MIN(DewPoint), AVG(Temperature)," 17142 " MIN(SetPoint), MAX(SetPoint), AVG(SetPoint) " 17143 "FROM Temperature WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 17144 idx, szDateEnd.c_str()); 17145 if (!result.empty()) 17146 { 17147 std::vector<std::string> sd = result[0]; 17148 17149 root["result"][ii]["d"] = szDateEnd; 17150 if (sendTemp) 17151 { 17152 double te = ConvertTemperature(atof(sd[1].c_str()), tempsign); 17153 double tm = ConvertTemperature(atof(sd[0].c_str()), tempsign); 17154 double ta = ConvertTemperature(atof(sd[7].c_str()), tempsign); 17155 17156 root["result"][ii]["te"] = te; 17157 root["result"][ii]["tm"] = tm; 17158 root["result"][ii]["ta"] = ta; 17159 } 17160 if (sendChill) 17161 { 17162 double ch = ConvertTemperature(atof(sd[3].c_str()), tempsign); 17163 double cm = ConvertTemperature(atof(sd[2].c_str()), tempsign); 17164 root["result"][ii]["ch"] = ch; 17165 root["result"][ii]["cm"] = cm; 17166 } 17167 if (sendHum) 17168 { 17169 root["result"][ii]["hu"] = sd[4]; 17170 } 17171 if (sendBaro) 17172 { 17173 if (dType == pTypeTEMP_HUM_BARO) 17174 { 17175 if (dSubType == sTypeTHBFloat) 17176 { 17177 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 17178 root["result"][ii]["ba"] = szTmp; 17179 } 17180 else 17181 root["result"][ii]["ba"] = sd[5]; 17182 } 17183 else if (dType == pTypeTEMP_BARO) 17184 { 17185 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 17186 root["result"][ii]["ba"] = szTmp; 17187 } 17188 else if ((dType == pTypeGeneral) && (dSubType == sTypeBaro)) 17189 { 17190 sprintf(szTmp, "%.1f", atof(sd[5].c_str()) / 10.0f); 17191 root["result"][ii]["ba"] = szTmp; 17192 } 17193 } 17194 if (sendDew) 17195 { 17196 double dp = ConvertTemperature(atof(sd[6].c_str()), tempsign); 17197 root["result"][ii]["dp"] = dp; 17198 } 17199 if (sendSet) 17200 { 17201 double sm = ConvertTemperature(atof(sd[8].c_str()), tempsign); 17202 double sx = ConvertTemperature(atof(sd[9].c_str()), tempsign); 17203 double se = ConvertTemperature(atof(sd[10].c_str()), tempsign); 17204 17205 root["result"][ii]["sm"] = sm; 17206 root["result"][ii]["se"] = se; 17207 root["result"][ii]["sx"] = sx; 17208 } 17209 ii++; 17210 } 17211 } 17212 } 17213 else if (sensor == "uv") { 17214 root["status"] = "OK"; 17215 root["title"] = "Graph " + sensor + " " + srange; 17216 17217 result = m_sql.safe_query( 17218 "SELECT Level, Date FROM %s WHERE (DeviceRowID==%" PRIu64 "" 17219 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", 17220 dbasetable.c_str(), idx, szDateStart.c_str(), szDateEnd.c_str()); 17221 int ii = 0; 17222 if (!result.empty()) 17223 { 17224 for (const auto & itt : result) 17225 { 17226 std::vector<std::string> sd = itt; 17227 17228 root["result"][ii]["d"] = sd[1].substr(0, 16); 17229 root["result"][ii]["uvi"] = sd[0]; 17230 ii++; 17231 } 17232 } 17233 //add today (have to calculate it) 17234 result = m_sql.safe_query( 17235 "SELECT MAX(Level) FROM UV WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 17236 idx, szDateEnd.c_str()); 17237 if (!result.empty()) 17238 { 17239 std::vector<std::string> sd = result[0]; 17240 17241 root["result"][ii]["d"] = szDateEnd; 17242 root["result"][ii]["uvi"] = sd[0]; 17243 ii++; 17244 } 17245 } 17246 else if (sensor == "rain") { 17247 root["status"] = "OK"; 17248 root["title"] = "Graph " + sensor + " " + srange; 17249 17250 result = m_sql.safe_query( 17251 "SELECT Total, Rate, Date FROM %s " 17252 "WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", 17253 dbasetable.c_str(), idx, szDateStart.c_str(), szDateEnd.c_str()); 17254 int ii = 0; 17255 if (!result.empty()) 17256 { 17257 for (const auto & itt : result) 17258 { 17259 std::vector<std::string> sd = itt; 17260 17261 root["result"][ii]["d"] = sd[2].substr(0, 16); 17262 root["result"][ii]["mm"] = sd[0]; 17263 ii++; 17264 } 17265 } 17266 //add today (have to calculate it) 17267 if (dSubType == sTypeRAINWU || dSubType == sTypeRAINByRate) 17268 { 17269 result = m_sql.safe_query( 17270 "SELECT Total, Total, Rate FROM Rain WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q') ORDER BY ROWID DESC LIMIT 1", 17271 idx, szDateEnd.c_str()); 17272 } 17273 else 17274 { 17275 result = m_sql.safe_query( 17276 "SELECT MIN(Total), MAX(Total), MAX(Rate) FROM Rain WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 17277 idx, szDateEnd.c_str()); 17278 } 17279 if (!result.empty()) 17280 { 17281 std::vector<std::string> sd = result[0]; 17282 17283 float total_min = static_cast<float>(atof(sd[0].c_str())); 17284 float total_max = static_cast<float>(atof(sd[1].c_str())); 17285 //int rate = atoi(sd[2].c_str()); 17286 17287 float total_real = 0; 17288 if (dSubType == sTypeRAINWU || dSubType == sTypeRAINByRate) 17289 { 17290 total_real = total_max; 17291 } 17292 else 17293 { 17294 total_real = total_max - total_min; 17295 } 17296 sprintf(szTmp, "%.1f", total_real); 17297 root["result"][ii]["d"] = szDateEnd; 17298 root["result"][ii]["mm"] = szTmp; 17299 ii++; 17300 } 17301 } 17302 else if (sensor == "counter") { 17303 root["status"] = "OK"; 17304 root["title"] = "Graph " + sensor + " " + srange; 17305 root["ValueQuantity"] = options["ValueQuantity"]; 17306 root["ValueUnits"] = options["ValueUnits"]; 17307 17308 int ii = 0; 17309 if (dType == pTypeP1Power) 17310 { 17311 result = m_sql.safe_query( 17312 "SELECT Value1,Value2,Value5,Value6, Date " 17313 "FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q'" 17314 " AND Date<='%q') ORDER BY Date ASC", 17315 dbasetable.c_str(), idx, szDateStart.c_str(), szDateEnd.c_str()); 17316 if (!result.empty()) 17317 { 17318 bool bHaveDeliverd = false; 17319 for (const auto & itt : result) 17320 { 17321 std::vector<std::string> sd = itt; 17322 17323 root["result"][ii]["d"] = sd[4].substr(0, 16); 17324 17325 std::string szUsage1 = sd[0]; 17326 std::string szDeliv1 = sd[1]; 17327 std::string szUsage2 = sd[2]; 17328 std::string szDeliv2 = sd[3]; 17329 17330 float fUsage = (float)(atof(szUsage1.c_str()) + atof(szUsage2.c_str())); 17331 float fDeliv = (float)(atof(szDeliv1.c_str()) + atof(szDeliv2.c_str())); 17332 17333 if (fDeliv != 0) 17334 bHaveDeliverd = true; 17335 sprintf(szTmp, "%.3f", fUsage / divider); 17336 root["result"][ii]["v"] = szTmp; 17337 sprintf(szTmp, "%.3f", fDeliv / divider); 17338 root["result"][ii]["v2"] = szTmp; 17339 ii++; 17340 } 17341 if (bHaveDeliverd) 17342 { 17343 root["delivered"] = true; 17344 } 17345 } 17346 } 17347 else 17348 { 17349 result = m_sql.safe_query("SELECT Value, Date FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q' AND Date<='%q') ORDER BY Date ASC", dbasetable.c_str(), idx, szDateStart.c_str(), szDateEnd.c_str()); 17350 if (!result.empty()) 17351 { 17352 for (const auto & itt : result) 17353 { 17354 std::vector<std::string> sd = itt; 17355 17356 std::string szValue = sd[0]; 17357 switch (metertype) 17358 { 17359 case MTYPE_ENERGY: 17360 case MTYPE_ENERGY_GENERATED: 17361 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 17362 szValue = szTmp; 17363 break; 17364 case MTYPE_GAS: 17365 sprintf(szTmp, "%.2f", atof(szValue.c_str()) / divider); 17366 szValue = szTmp; 17367 break; 17368 case MTYPE_WATER: 17369 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 17370 szValue = szTmp; 17371 break; 17372 } 17373 root["result"][ii]["d"] = sd[1].substr(0, 16); 17374 root["result"][ii]["v"] = szValue; 17375 ii++; 17376 } 17377 } 17378 } 17379 //add today (have to calculate it) 17380 if (dType == pTypeP1Power) 17381 { 17382 result = m_sql.safe_query( 17383 "SELECT MIN(Value1), MAX(Value1), MIN(Value2)," 17384 " MAX(Value2),MIN(Value5), MAX(Value5)," 17385 " MIN(Value6), MAX(Value6) " 17386 "FROM MultiMeter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 17387 idx, szDateEnd.c_str()); 17388 bool bHaveDeliverd = false; 17389 if (!result.empty()) 17390 { 17391 std::vector<std::string> sd = result[0]; 17392 17393 unsigned long long total_min_usage_1 = std::strtoull(sd[0].c_str(), nullptr, 10); 17394 unsigned long long total_max_usage_1 = std::strtoull(sd[1].c_str(), nullptr, 10); 17395 unsigned long long total_min_usage_2 = std::strtoull(sd[4].c_str(), nullptr, 10); 17396 unsigned long long total_max_usage_2 = std::strtoull(sd[5].c_str(), nullptr, 10); 17397 unsigned long long total_real_usage; 17398 17399 unsigned long long total_min_deliv_1 = std::strtoull(sd[2].c_str(), nullptr, 10); 17400 unsigned long long total_max_deliv_1 = std::strtoull(sd[3].c_str(), nullptr, 10); 17401 unsigned long long total_min_deliv_2 = std::strtoull(sd[6].c_str(), nullptr, 10); 17402 unsigned long long total_max_deliv_2 = std::strtoull(sd[7].c_str(), nullptr, 10); 17403 unsigned long long total_real_deliv; 17404 17405 total_real_usage = (total_max_usage_1 + total_max_usage_2) - (total_min_usage_1 + total_min_usage_2); 17406 total_real_deliv = (total_max_deliv_1 + total_max_deliv_2) - (total_min_deliv_1 + total_min_deliv_2); 17407 17408 if (total_real_deliv != 0) 17409 bHaveDeliverd = true; 17410 17411 root["result"][ii]["d"] = szDateEnd; 17412 17413 sprintf(szTmp, "%llu", total_real_usage); 17414 std::string szValue = szTmp; 17415 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 17416 root["result"][ii]["v"] = szTmp; 17417 sprintf(szTmp, "%llu", total_real_deliv); 17418 szValue = szTmp; 17419 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 17420 root["result"][ii]["v2"] = szTmp; 17421 ii++; 17422 if (bHaveDeliverd) 17423 { 17424 root["delivered"] = true; 17425 } 17426 } 17427 } 17428 else if (!bIsManagedCounter) 17429 { 17430 result = m_sql.safe_query( 17431 "SELECT MIN(Value), MAX(Value) FROM Meter WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q')", 17432 idx, szDateEnd.c_str()); 17433 if (!result.empty()) 17434 { 17435 std::vector<std::string> sd = result[0]; 17436 unsigned long long total_min = std::strtoull(sd[0].c_str(), nullptr, 10); 17437 unsigned long long total_max = std::strtoull(sd[1].c_str(), nullptr, 10); 17438 unsigned long long total_real; 17439 17440 total_real = total_max - total_min; 17441 sprintf(szTmp, "%llu", total_real); 17442 17443 std::string szValue = szTmp; 17444 switch (metertype) 17445 { 17446 case MTYPE_ENERGY: 17447 case MTYPE_ENERGY_GENERATED: 17448 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 17449 szValue = szTmp; 17450 break; 17451 case MTYPE_GAS: 17452 sprintf(szTmp, "%.2f", atof(szValue.c_str()) / divider); 17453 szValue = szTmp; 17454 break; 17455 case MTYPE_WATER: 17456 sprintf(szTmp, "%.3f", atof(szValue.c_str()) / divider); 17457 szValue = szTmp; 17458 break; 17459 } 17460 17461 root["result"][ii]["d"] = szDateEnd; 17462 root["result"][ii]["v"] = szValue; 17463 ii++; 17464 } 17465 } 17466 } 17467 else if (sensor == "wind") { 17468 root["status"] = "OK"; 17469 root["title"] = "Graph " + sensor + " " + srange; 17470 17471 int ii = 0; 17472 17473 result = m_sql.safe_query( 17474 "SELECT Direction, Speed_Min, Speed_Max, Gust_Min," 17475 " Gust_Max, Date " 17476 "FROM %s WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q'" 17477 " AND Date<='%q') ORDER BY Date ASC", 17478 dbasetable.c_str(), idx, szDateStart.c_str(), szDateEnd.c_str()); 17479 if (!result.empty()) 17480 { 17481 for (const auto & itt : result) 17482 { 17483 std::vector<std::string> sd = itt; 17484 17485 root["result"][ii]["d"] = sd[5].substr(0, 16); 17486 root["result"][ii]["di"] = sd[0]; 17487 17488 int intSpeed = atoi(sd[2].c_str()); 17489 int intGust = atoi(sd[4].c_str()); 17490 if (m_sql.m_windunit != WINDUNIT_Beaufort) 17491 { 17492 sprintf(szTmp, "%.1f", float(intSpeed) * m_sql.m_windscale); 17493 root["result"][ii]["sp"] = szTmp; 17494 sprintf(szTmp, "%.1f", float(intGust) * m_sql.m_windscale); 17495 root["result"][ii]["gu"] = szTmp; 17496 } 17497 else 17498 { 17499 float windspeedms = float(intSpeed)*0.1f; 17500 float windgustms = float(intGust)*0.1f; 17501 sprintf(szTmp, "%d", MStoBeaufort(windspeedms)); 17502 root["result"][ii]["sp"] = szTmp; 17503 sprintf(szTmp, "%d", MStoBeaufort(windgustms)); 17504 root["result"][ii]["gu"] = szTmp; 17505 } 17506 ii++; 17507 } 17508 } 17509 //add today (have to calculate it) 17510 result = m_sql.safe_query( 17511 "SELECT AVG(Direction), MIN(Speed), MAX(Speed), MIN(Gust), MAX(Gust) FROM Wind WHERE (DeviceRowID==%" PRIu64 " AND Date>='%q') ORDER BY Date ASC", 17512 idx, szDateEnd.c_str()); 17513 if (!result.empty()) 17514 { 17515 std::vector<std::string> sd = result[0]; 17516 17517 root["result"][ii]["d"] = szDateEnd; 17518 root["result"][ii]["di"] = sd[0]; 17519 17520 int intSpeed = atoi(sd[2].c_str()); 17521 int intGust = atoi(sd[4].c_str()); 17522 if (m_sql.m_windunit != WINDUNIT_Beaufort) 17523 { 17524 sprintf(szTmp, "%.1f", float(intSpeed) * m_sql.m_windscale); 17525 root["result"][ii]["sp"] = szTmp; 17526 sprintf(szTmp, "%.1f", float(intGust) * m_sql.m_windscale); 17527 root["result"][ii]["gu"] = szTmp; 17528 } 17529 else 17530 { 17531 float windspeedms = float(intSpeed)*0.1f; 17532 float windgustms = float(intGust)*0.1f; 17533 sprintf(szTmp, "%d", MStoBeaufort(windspeedms)); 17534 root["result"][ii]["sp"] = szTmp; 17535 sprintf(szTmp, "%d", MStoBeaufort(windgustms)); 17536 root["result"][ii]["gu"] = szTmp; 17537 } 17538 ii++; 17539 } 17540 } 17541 }//custom range 17542 } 17543 17544 /** 17545 * Retrieve user session from store, without remote host. 17546 */ GetSession(const std::string & sessionId)17547 const WebEmStoredSession CWebServer::GetSession(const std::string & sessionId) { 17548 //_log.Log(LOG_STATUS, "SessionStore : get..."); 17549 WebEmStoredSession session; 17550 17551 if (sessionId.empty()) { 17552 _log.Log(LOG_ERROR, "SessionStore : cannot get session without id."); 17553 } 17554 else { 17555 std::vector<std::vector<std::string> > result; 17556 result = m_sql.safe_query("SELECT SessionID, Username, AuthToken, ExpirationDate FROM UserSessions WHERE SessionID = '%q'", 17557 sessionId.c_str()); 17558 if (!result.empty()) { 17559 session.id = result[0][0].c_str(); 17560 session.username = base64_decode(result[0][1]); 17561 session.auth_token = result[0][2].c_str(); 17562 17563 std::string sExpirationDate = result[0][3]; 17564 //time_t now = mytime(NULL); 17565 struct tm tExpirationDate; 17566 ParseSQLdatetime(session.expires, tExpirationDate, sExpirationDate); 17567 // RemoteHost is not used to restore the session 17568 // LastUpdate is not used to restore the session 17569 } 17570 } 17571 17572 return session; 17573 } 17574 17575 /** 17576 * Save user session. 17577 */ StoreSession(const WebEmStoredSession & session)17578 void CWebServer::StoreSession(const WebEmStoredSession & session) { 17579 //_log.Log(LOG_STATUS, "SessionStore : store..."); 17580 if (session.id.empty()) { 17581 _log.Log(LOG_ERROR, "SessionStore : cannot store session without id."); 17582 return; 17583 } 17584 17585 char szExpires[30]; 17586 struct tm ltime; 17587 localtime_r(&session.expires, <ime); 17588 strftime(szExpires, sizeof(szExpires), "%Y-%m-%d %H:%M:%S", <ime); 17589 17590 std::string remote_host = (session.remote_host.size() <= 50) ? // IPv4 : 15, IPv6 : (39|45) 17591 session.remote_host : session.remote_host.substr(0, 50); 17592 17593 WebEmStoredSession storedSession = GetSession(session.id); 17594 if (storedSession.id.empty()) { 17595 m_sql.safe_query( 17596 "INSERT INTO UserSessions (SessionID, Username, AuthToken, ExpirationDate, RemoteHost) VALUES ('%q', '%q', '%q', '%q', '%q')", 17597 session.id.c_str(), 17598 base64_encode(session.username).c_str(), 17599 session.auth_token.c_str(), 17600 szExpires, 17601 remote_host.c_str()); 17602 } 17603 else { 17604 m_sql.safe_query( 17605 "UPDATE UserSessions set AuthToken = '%q', ExpirationDate = '%q', RemoteHost = '%q', LastUpdate = datetime('now', 'localtime') WHERE SessionID = '%q'", 17606 session.auth_token.c_str(), 17607 szExpires, 17608 remote_host.c_str(), 17609 session.id.c_str()); 17610 } 17611 } 17612 17613 /** 17614 * Remove user session and expired sessions. 17615 */ RemoveSession(const std::string & sessionId)17616 void CWebServer::RemoveSession(const std::string & sessionId) { 17617 //_log.Log(LOG_STATUS, "SessionStore : remove..."); 17618 if (sessionId.empty()) { 17619 return; 17620 } 17621 m_sql.safe_query( 17622 "DELETE FROM UserSessions WHERE SessionID = '%q'", 17623 sessionId.c_str()); 17624 } 17625 17626 /** 17627 * Remove all expired user sessions. 17628 */ CleanSessions()17629 void CWebServer::CleanSessions() { 17630 //_log.Log(LOG_STATUS, "SessionStore : clean..."); 17631 m_sql.safe_query( 17632 "DELETE FROM UserSessions WHERE ExpirationDate < datetime('now', 'localtime')"); 17633 } 17634 17635 /** 17636 * Delete all user's session, except the session used to modify the username or password. 17637 * username must have been hashed 17638 * 17639 * Note : on the WebUserName modification, this method will not delete the session, but the session will be deleted anyway 17640 * because the username will be unknown (see cWebemRequestHandler::checkAuthToken). 17641 */ RemoveUsersSessions(const std::string & username,const WebEmSession & exceptSession)17642 void CWebServer::RemoveUsersSessions(const std::string& username, const WebEmSession & exceptSession) { 17643 m_sql.safe_query("DELETE FROM UserSessions WHERE (Username=='%q') and (SessionID!='%q')", username.c_str(), exceptSession.id.c_str()); 17644 } 17645 17646 } //server 17647 }//http 17648