MainFlowControl.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. #include "MainFlowControl.h"
  2. #include <string>
  3. #include <vector>
  4. #include "string.h"
  5. #include "esp_log.h"
  6. #include <iomanip>
  7. #include <sstream>
  8. #include "../../include/defines.h"
  9. #include "Helper.h"
  10. #include "statusled.h"
  11. #include "esp_camera.h"
  12. #include "time_sntp.h"
  13. #include "ClassControllCamera.h"
  14. #include "ClassFlowControll.h"
  15. #include "ClassLogFile.h"
  16. #include "server_GPIO.h"
  17. #include "server_file.h"
  18. #include "read_wlanini.h"
  19. #include "connect_wlan.h"
  20. #include "psram.h"
  21. ClassFlowControll flowctrl;
  22. TaskHandle_t xHandletask_autodoFlow = NULL;
  23. bool bTaskAutoFlowCreated = false;
  24. bool flowisrunning = false;
  25. long auto_interval = 0;
  26. bool auto_isrunning = false;
  27. int countRounds = 0;
  28. bool isPlannedReboot = false;
  29. static const char *TAG = "MAINCTRL";
  30. //#define DEBUG_DETAIL_ON
  31. void CheckIsPlannedReboot()
  32. {
  33. FILE *pfile;
  34. if ((pfile = fopen("/sdcard/reboot.txt", "r")) == NULL) {
  35. //LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Initial boot or not a planned reboot");
  36. isPlannedReboot = false;
  37. }
  38. else {
  39. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Planned reboot");
  40. DeleteFile("/sdcard/reboot.txt"); // Prevent Boot Loop!!!
  41. isPlannedReboot = true;
  42. }
  43. }
  44. bool getIsPlannedReboot()
  45. {
  46. return isPlannedReboot;
  47. }
  48. int getCountFlowRounds()
  49. {
  50. return countRounds;
  51. }
  52. esp_err_t GetJPG(std::string _filename, httpd_req_t *req)
  53. {
  54. return flowctrl.GetJPGStream(_filename, req);
  55. }
  56. esp_err_t GetRawJPG(httpd_req_t *req)
  57. {
  58. return flowctrl.SendRawJPG(req);
  59. }
  60. bool isSetupModusActive()
  61. {
  62. return flowctrl.getStatusSetupModus();
  63. }
  64. void DeleteMainFlowTask()
  65. {
  66. #ifdef DEBUG_DETAIL_ON
  67. ESP_LOGD(TAG, "DeleteMainFlowTask: xHandletask_autodoFlow: %ld", (long) xHandletask_autodoFlow);
  68. #endif
  69. if( xHandletask_autodoFlow != NULL )
  70. {
  71. vTaskDelete(xHandletask_autodoFlow);
  72. xHandletask_autodoFlow = NULL;
  73. }
  74. #ifdef DEBUG_DETAIL_ON
  75. ESP_LOGD(TAG, "Killed: xHandletask_autodoFlow");
  76. #endif
  77. }
  78. void doInit(void)
  79. {
  80. #ifdef DEBUG_DETAIL_ON
  81. ESP_LOGD(TAG, "Start flowctrl.InitFlow(config);");
  82. #endif
  83. flowctrl.InitFlow(CONFIG_FILE);
  84. #ifdef DEBUG_DETAIL_ON
  85. ESP_LOGD(TAG, "Finished flowctrl.InitFlow(config);");
  86. #endif
  87. /* GPIO handler has to be initialized before MQTT init to ensure proper topic subscription */
  88. gpio_handler_init();
  89. #ifdef ENABLE_MQTT
  90. flowctrl.StartMQTTService();
  91. #endif //ENABLE_MQTT
  92. }
  93. bool doflow(void)
  94. {
  95. std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT);
  96. ESP_LOGD(TAG, "doflow - start %s", zw_time.c_str());
  97. flowisrunning = true;
  98. flowctrl.doFlow(zw_time);
  99. flowisrunning = false;
  100. #ifdef DEBUG_DETAIL_ON
  101. ESP_LOGD(TAG, "doflow - end %s", zw_time.c_str());
  102. #endif
  103. return true;
  104. }
  105. esp_err_t handler_get_heap(httpd_req_t *req)
  106. {
  107. #ifdef DEBUG_DETAIL_ON
  108. LogFile.WriteHeapInfo("handler_get_heap - Start");
  109. ESP_LOGD(TAG, "handler_get_heap uri: %s", req->uri);
  110. #endif
  111. std::string zw = "Heap info:<br>" + getESPHeapInfo();
  112. #ifdef TASK_ANALYSIS_ON
  113. char* pcTaskList = (char*) calloc_psram_heap(std::string(TAG) + "->pcTaskList", 1, sizeof(char) * 768, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
  114. if (pcTaskList) {
  115. vTaskList(pcTaskList);
  116. zw = zw + "<br><br>Task info:<br><pre>Name | State | Prio | Lowest stacksize | Creation order | CPU (-1=NoAffinity)<br>"
  117. + std::string(pcTaskList) + "</pre>";
  118. free_psram_heap(std::string(TAG) + "->pcTaskList", pcTaskList);
  119. }
  120. else {
  121. zw = zw + "<br><br>Task info:<br>ERROR - Allocation of TaskList buffer in PSRAM failed";
  122. }
  123. #endif
  124. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  125. if (zw.length() > 0)
  126. {
  127. httpd_resp_send(req, zw.c_str(), zw.length());
  128. }
  129. else
  130. {
  131. httpd_resp_send(req, NULL, 0);
  132. }
  133. #ifdef DEBUG_DETAIL_ON
  134. LogFile.WriteHeapInfo("handler_get_heap - Done");
  135. #endif
  136. return ESP_OK;
  137. }
  138. esp_err_t handler_init(httpd_req_t *req)
  139. {
  140. #ifdef DEBUG_DETAIL_ON
  141. LogFile.WriteHeapInfo("handler_init - Start");
  142. ESP_LOGD(TAG, "handler_doinit uri: %s", req->uri);
  143. #endif
  144. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  145. const char* resp_str = "Init started<br>";
  146. httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
  147. doInit();
  148. resp_str = "Init done<br>";
  149. httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
  150. #ifdef DEBUG_DETAIL_ON
  151. LogFile.WriteHeapInfo("handler_init - Done");
  152. #endif
  153. return ESP_OK;
  154. }
  155. esp_err_t handler_stream(httpd_req_t *req)
  156. {
  157. #ifdef DEBUG_DETAIL_ON
  158. LogFile.WriteHeapInfo("handler_stream - Start");
  159. ESP_LOGD(TAG, "handler_stream uri: %s", req->uri);
  160. #endif
  161. char _query[50];
  162. char _value[10];
  163. bool flashlightOn = false;
  164. if (httpd_req_get_url_query_str(req, _query, 50) == ESP_OK)
  165. {
  166. // ESP_LOGD(TAG, "Query: %s", _query);
  167. if (httpd_query_key_value(_query, "flashlight", _value, 10) == ESP_OK)
  168. {
  169. #ifdef DEBUG_DETAIL_ON
  170. ESP_LOGD(TAG, "flashlight is found%s", _size);
  171. #endif
  172. if (strlen(_value) > 0)
  173. flashlightOn = true;
  174. }
  175. }
  176. Camera.CaptureToStream(req, flashlightOn);
  177. #ifdef DEBUG_DETAIL_ON
  178. LogFile.WriteHeapInfo("handler_stream - Done");
  179. #endif
  180. return ESP_OK;
  181. }
  182. esp_err_t handler_flow_start(httpd_req_t *req) {
  183. #ifdef DEBUG_DETAIL_ON
  184. LogFile.WriteHeapInfo("handler_flow_start - Start");
  185. #endif
  186. ESP_LOGD(TAG, "handler_flow_start uri: %s", req->uri);
  187. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  188. if (auto_isrunning) {
  189. xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action
  190. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by REST API /flow_start");
  191. const char* resp_str = "The flow is going to be started immediately or is already running";
  192. httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
  193. }
  194. else {
  195. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by REST API, but flow is not active!");
  196. const char* resp_str = "WARNING: Flow start triggered by REST API, but flow is not active";
  197. httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
  198. }
  199. #ifdef DEBUG_DETAIL_ON
  200. LogFile.WriteHeapInfo("handler_flow_start - Done");
  201. #endif
  202. return ESP_OK;
  203. }
  204. #ifdef ENABLE_MQTT
  205. esp_err_t MQTTCtrlFlowStart(std::string _topic) {
  206. #ifdef DEBUG_DETAIL_ON
  207. LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Start");
  208. #endif
  209. ESP_LOGD(TAG, "MQTTCtrlFlowStart: topic %s", _topic.c_str());
  210. if (auto_isrunning)
  211. {
  212. xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action
  213. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by MQTT topic " + _topic);
  214. }
  215. else
  216. {
  217. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Flow start triggered by MQTT topic " + _topic + ", but flow is not active!");
  218. }
  219. #ifdef DEBUG_DETAIL_ON
  220. LogFile.WriteHeapInfo("MQTTCtrlFlowStart - Done");
  221. #endif
  222. return ESP_OK;
  223. }
  224. #endif //ENABLE_MQTT
  225. esp_err_t handler_json(httpd_req_t *req)
  226. {
  227. #ifdef DEBUG_DETAIL_ON
  228. LogFile.WriteHeapInfo("handler_json - Start");
  229. #endif
  230. ESP_LOGD(TAG, "handler_JSON uri: %s", req->uri);
  231. if (bTaskAutoFlowCreated)
  232. {
  233. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  234. httpd_resp_set_type(req, "application/json");
  235. std::string zw = flowctrl.getJSON();
  236. if (zw.length() > 0)
  237. {
  238. httpd_resp_send(req, zw.c_str(), zw.length());
  239. }
  240. else
  241. {
  242. httpd_resp_send(req, NULL, 0);
  243. }
  244. }
  245. else
  246. {
  247. httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /json not yet available!");
  248. return ESP_ERR_NOT_FOUND;
  249. }
  250. #ifdef DEBUG_DETAIL_ON
  251. LogFile.WriteHeapInfo("handler_JSON - Done");
  252. #endif
  253. return ESP_OK;
  254. }
  255. esp_err_t handler_wasserzaehler(httpd_req_t *req)
  256. {
  257. #ifdef DEBUG_DETAIL_ON
  258. LogFile.WriteHeapInfo("handler water counter - Start");
  259. #endif
  260. if (bTaskAutoFlowCreated)
  261. {
  262. bool _rawValue = false;
  263. bool _noerror = false;
  264. bool _all = false;
  265. std::string _type = "value";
  266. string zw;
  267. ESP_LOGD(TAG, "handler water counter uri: %s", req->uri);
  268. char _query[100];
  269. char _size[10];
  270. if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
  271. {
  272. // ESP_LOGD(TAG, "Query: %s", _query);
  273. if (httpd_query_key_value(_query, "all", _size, 10) == ESP_OK)
  274. {
  275. #ifdef DEBUG_DETAIL_ON
  276. ESP_LOGD(TAG, "all is found%s", _size);
  277. #endif
  278. _all = true;
  279. }
  280. if (httpd_query_key_value(_query, "type", _size, 10) == ESP_OK)
  281. {
  282. #ifdef DEBUG_DETAIL_ON
  283. ESP_LOGD(TAG, "all is found: %s", _size);
  284. #endif
  285. _type = std::string(_size);
  286. }
  287. if (httpd_query_key_value(_query, "rawvalue", _size, 10) == ESP_OK)
  288. {
  289. #ifdef DEBUG_DETAIL_ON
  290. ESP_LOGD(TAG, "rawvalue is found: %s", _size);
  291. #endif
  292. _rawValue = true;
  293. }
  294. if (httpd_query_key_value(_query, "noerror", _size, 10) == ESP_OK)
  295. {
  296. #ifdef DEBUG_DETAIL_ON
  297. ESP_LOGD(TAG, "noerror is found: %s", _size);
  298. #endif
  299. _noerror = true;
  300. }
  301. }
  302. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  303. if (_all)
  304. {
  305. httpd_resp_set_type(req, "text/plain");
  306. ESP_LOGD(TAG, "TYPE: %s", _type.c_str());
  307. int _intype = READOUT_TYPE_VALUE;
  308. if (_type == "prevalue")
  309. _intype = READOUT_TYPE_PREVALUE;
  310. if (_type == "raw")
  311. _intype = READOUT_TYPE_RAWVALUE;
  312. if (_type == "error")
  313. _intype = READOUT_TYPE_ERROR;
  314. zw = flowctrl.getReadoutAll(_intype);
  315. ESP_LOGD(TAG, "ZW: %s", zw.c_str());
  316. if (zw.length() > 0)
  317. httpd_resp_send(req, zw.c_str(), zw.length());
  318. return ESP_OK;
  319. }
  320. std::string *status = flowctrl.getActStatus();
  321. string query = std::string(_query);
  322. // ESP_LOGD(TAG, "Query: %s, query.c_str());
  323. if (query.find("full") != std::string::npos)
  324. {
  325. string txt;
  326. txt = "<body style=\"font-family: arial\">";
  327. if ((countRounds <= 1) && (*status != std::string("Flow finished"))) { // First round not completed yet
  328. txt += "<h3>Please wait for the first round to complete!</h3><h3>Current state: " + *status + "</h3>\n";
  329. }
  330. else {
  331. txt += "<h3>Value</h3>";
  332. }
  333. httpd_resp_sendstr_chunk(req, txt.c_str());
  334. }
  335. zw = flowctrl.getReadout(_rawValue, _noerror, 0);
  336. if (zw.length() > 0)
  337. httpd_resp_sendstr_chunk(req, zw.c_str());
  338. if (query.find("full") != std::string::npos)
  339. {
  340. string txt, zw;
  341. if ((countRounds <= 1) && (*status != std::string("Flow finished"))) { // First round not completed yet
  342. // Nothing to do
  343. }
  344. else {
  345. /* Digital ROIs */
  346. txt = "<body style=\"font-family: arial\">";
  347. txt += "<h3>Recognized Digit ROIs (previous round)</h3>\n";
  348. txt += "<table style=\"border-spacing: 5px\"><tr style=\"text-align: center; vertical-align: top;\">\n";
  349. std::vector<HTMLInfo*> htmlinfodig;
  350. htmlinfodig = flowctrl.GetAllDigital();
  351. for (int i = 0; i < htmlinfodig.size(); ++i)
  352. {
  353. if (flowctrl.GetTypeDigital() == Digital)
  354. {
  355. if (htmlinfodig[i]->val == 10)
  356. zw = "NaN";
  357. else
  358. zw = to_string((int) htmlinfodig[i]->val);
  359. txt += "<td style=\"width: 100px\"><h4>" + zw + "</h4><p><img src=\"/img_tmp/" + htmlinfodig[i]->filename + "\"></p></td>\n";
  360. }
  361. else
  362. {
  363. std::stringstream stream;
  364. stream << std::fixed << std::setprecision(1) << htmlinfodig[i]->val;
  365. zw = stream.str();
  366. txt += "<td style=\"width: 100px\"><h4>" + zw + "</h4><p><img src=\"/img_tmp/" + htmlinfodig[i]->filename + "\"></p></td>\n";
  367. }
  368. delete htmlinfodig[i];
  369. }
  370. htmlinfodig.clear();
  371. txt += "</tr></table>\n";
  372. httpd_resp_sendstr_chunk(req, txt.c_str());
  373. /* Analog ROIs */
  374. txt = "<h3>Recognized Analog ROIs (previous round)</h3>\n";
  375. txt += "<table style=\"border-spacing: 5px\"><tr style=\"text-align: center; vertical-align: top;\">\n";
  376. std::vector<HTMLInfo*> htmlinfoana;
  377. htmlinfoana = flowctrl.GetAllAnalog();
  378. for (int i = 0; i < htmlinfoana.size(); ++i)
  379. {
  380. std::stringstream stream;
  381. stream << std::fixed << std::setprecision(1) << htmlinfoana[i]->val;
  382. zw = stream.str();
  383. txt += "<td style=\"width: 150px;\"><h4>" + zw + "</h4><p><img src=\"/img_tmp/" + htmlinfoana[i]->filename + "\"></p></td>\n";
  384. delete htmlinfoana[i];
  385. }
  386. htmlinfoana.clear();
  387. txt += "</tr>\n</table>\n";
  388. httpd_resp_sendstr_chunk(req, txt.c_str());
  389. /* Full Image
  390. * Only show it after the image got taken and aligned */
  391. txt = "<h3>Aligned Image (current round)</h3>\n";
  392. if ((*status == std::string("Initialization")) ||
  393. (*status == std::string("Initialization (delayed)")) ||
  394. (*status == std::string("Take Image"))) {
  395. txt += "<p>Current state: " + *status + "</p>\n";
  396. }
  397. else {
  398. txt += "<img src=\"/img_tmp/alg_roi.jpg\">\n";
  399. }
  400. httpd_resp_sendstr_chunk(req, txt.c_str());
  401. }
  402. }
  403. /* Respond with an empty chunk to signal HTTP response completion */
  404. httpd_resp_sendstr_chunk(req, NULL);
  405. }
  406. else
  407. {
  408. httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Flow not (yet) started: REST API /value not available!");
  409. return ESP_ERR_NOT_FOUND;
  410. }
  411. #ifdef DEBUG_DETAIL_ON
  412. LogFile.WriteHeapInfo("handler_wasserzaehler - Done");
  413. #endif
  414. return ESP_OK;
  415. }
  416. esp_err_t handler_editflow(httpd_req_t *req)
  417. {
  418. #ifdef DEBUG_DETAIL_ON
  419. LogFile.WriteHeapInfo("handler_editflow - Start");
  420. #endif
  421. ESP_LOGD(TAG, "handler_editflow uri: %s", req->uri);
  422. char _query[200];
  423. char _valuechar[30];
  424. string _task;
  425. if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
  426. {
  427. if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK)
  428. {
  429. #ifdef DEBUG_DETAIL_ON
  430. ESP_LOGD(TAG, "task is found: %s", _valuechar);
  431. #endif
  432. _task = string(_valuechar);
  433. }
  434. }
  435. if (_task.compare("namenumbers") == 0)
  436. {
  437. ESP_LOGD(TAG, "Get NUMBER list");
  438. return get_numbers_file_handler(req);
  439. }
  440. if (_task.compare("data") == 0)
  441. {
  442. ESP_LOGD(TAG, "Get data list");
  443. return get_data_file_handler(req);
  444. }
  445. if (_task.compare("tflite") == 0)
  446. {
  447. ESP_LOGD(TAG, "Get tflite list");
  448. return get_tflite_file_handler(req);
  449. }
  450. if (_task.compare("copy") == 0)
  451. {
  452. string in, out, zw;
  453. httpd_query_key_value(_query, "in", _valuechar, 30);
  454. in = string(_valuechar);
  455. httpd_query_key_value(_query, "out", _valuechar, 30);
  456. out = string(_valuechar);
  457. #ifdef DEBUG_DETAIL_ON
  458. ESP_LOGD(TAG, "in: %s", in.c_str());
  459. ESP_LOGD(TAG, "out: %s", out.c_str());
  460. #endif
  461. in = "/sdcard" + in;
  462. out = "/sdcard" + out;
  463. CopyFile(in, out);
  464. zw = "Copy Done";
  465. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  466. httpd_resp_send(req, zw.c_str(), zw.length());
  467. }
  468. if (_task.compare("cutref") == 0)
  469. {
  470. string in, out, zw;
  471. int x, y, dx, dy;
  472. bool enhance = false;
  473. httpd_query_key_value(_query, "in", _valuechar, 30);
  474. in = string(_valuechar);
  475. httpd_query_key_value(_query, "out", _valuechar, 30);
  476. out = string(_valuechar);
  477. httpd_query_key_value(_query, "x", _valuechar, 30);
  478. zw = string(_valuechar);
  479. x = stoi(zw);
  480. httpd_query_key_value(_query, "y", _valuechar, 30);
  481. zw = string(_valuechar);
  482. y = stoi(zw);
  483. httpd_query_key_value(_query, "dx", _valuechar, 30);
  484. zw = string(_valuechar);
  485. dx = stoi(zw);
  486. httpd_query_key_value(_query, "dy", _valuechar, 30);
  487. zw = string(_valuechar);
  488. dy = stoi(zw);
  489. #ifdef DEBUG_DETAIL_ON
  490. ESP_LOGD(TAG, "in: %s", in.c_str());
  491. ESP_LOGD(TAG, "out: %s", out.c_str());
  492. ESP_LOGD(TAG, "x: %s", zw.c_str());
  493. ESP_LOGD(TAG, "y: %s", zw.c_str());
  494. ESP_LOGD(TAG, "dx: %s", zw.c_str());
  495. ESP_LOGD(TAG, "dy: %s", zw.c_str());
  496. #endif
  497. if (httpd_query_key_value(_query, "enhance", _valuechar, 10) == ESP_OK)
  498. {
  499. zw = string(_valuechar);
  500. if (zw.compare("true") == 0)
  501. {
  502. enhance = true;
  503. }
  504. }
  505. in = "/sdcard" + in;
  506. out = "/sdcard" + out;
  507. string out2 = out.substr(0, out.length() - 4) + "_org.jpg";
  508. CAlignAndCutImage *caic = new CAlignAndCutImage("cutref", in);
  509. caic->CutAndSave(out2, x, y, dx, dy);
  510. delete caic;
  511. CImageBasis *cim = new CImageBasis("cutref", out2);
  512. if (enhance)
  513. {
  514. cim->Contrast(90);
  515. }
  516. cim->SaveToFile(out);
  517. delete cim;
  518. zw = "CutImage Done";
  519. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  520. httpd_resp_send(req, zw.c_str(), zw.length());
  521. }
  522. if (_task.compare("test_take") == 0)
  523. {
  524. std::string _host = "";
  525. std::string _bri = "";
  526. std::string _con = "";
  527. std::string _sat = "";
  528. std::string _int = "";
  529. int bri = -100;
  530. int sat = -100;
  531. int con = -100;
  532. int intens = -100;
  533. if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) {
  534. _host = std::string(_valuechar);
  535. }
  536. if (httpd_query_key_value(_query, "int", _valuechar, 30) == ESP_OK) {
  537. _int = std::string(_valuechar);
  538. intens = stoi(_int);
  539. }
  540. if (httpd_query_key_value(_query, "bri", _valuechar, 30) == ESP_OK) {
  541. _bri = std::string(_valuechar);
  542. bri = stoi(_bri);
  543. }
  544. if (httpd_query_key_value(_query, "con", _valuechar, 30) == ESP_OK) {
  545. _con = std::string(_valuechar);
  546. con = stoi(_con);
  547. }
  548. if (httpd_query_key_value(_query, "sat", _valuechar, 30) == ESP_OK) {
  549. _sat = std::string(_valuechar);
  550. sat = stoi(_sat);
  551. }
  552. // ESP_LOGD(TAG, "Parameter host: %s", _host.c_str());
  553. // string zwzw = "Do " + _task + " start\n"; ESP_LOGD(TAG, zwzw.c_str());
  554. Camera.SetBrightnessContrastSaturation(bri, con, sat);
  555. Camera.SetLEDIntensity(intens);
  556. ESP_LOGD(TAG, "test_take - vor TakeImage");
  557. std::string zw = flowctrl.doSingleStep("[TakeImage]", _host);
  558. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  559. httpd_resp_send(req, zw.c_str(), zw.length());
  560. }
  561. if (_task.compare("test_align") == 0)
  562. {
  563. std::string _host = "";
  564. if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) {
  565. _host = std::string(_valuechar);
  566. }
  567. // ESP_LOGD(TAG, "Parameter host: %s", _host.c_str());
  568. // string zwzw = "Do " + _task + " start\n"; ESP_LOGD(TAG, zwzw.c_str());
  569. std::string zw = flowctrl.doSingleStep("[Alignment]", _host);
  570. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  571. httpd_resp_send(req, zw.c_str(), zw.length());
  572. }
  573. #ifdef DEBUG_DETAIL_ON
  574. LogFile.WriteHeapInfo("handler_editflow - Done");
  575. #endif
  576. return ESP_OK;
  577. }
  578. esp_err_t handler_statusflow(httpd_req_t *req)
  579. {
  580. #ifdef DEBUG_DETAIL_ON
  581. LogFile.WriteHeapInfo("handler_statusflow - Start");
  582. #endif
  583. const char* resp_str;
  584. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  585. if (bTaskAutoFlowCreated)
  586. {
  587. #ifdef DEBUG_DETAIL_ON
  588. ESP_LOGD(TAG, "handler_statusflow: %s", req->uri);
  589. #endif
  590. string* zw = flowctrl.getActStatusWithTime();
  591. resp_str = zw->c_str();
  592. httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
  593. }
  594. else
  595. {
  596. resp_str = "Flow task not yet created";
  597. httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
  598. }
  599. #ifdef DEBUG_DETAIL_ON
  600. LogFile.WriteHeapInfo("handler_statusflow - Done");
  601. #endif
  602. return ESP_OK;
  603. }
  604. esp_err_t handler_cputemp(httpd_req_t *req)
  605. {
  606. #ifdef DEBUG_DETAIL_ON
  607. LogFile.WriteHeapInfo("handler_cputemp - Start");
  608. #endif
  609. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  610. httpd_resp_send(req, std::to_string((int)temperatureRead()).c_str(), HTTPD_RESP_USE_STRLEN);
  611. #ifdef DEBUG_DETAIL_ON
  612. LogFile.WriteHeapInfo("handler_cputemp - End");
  613. #endif
  614. return ESP_OK;
  615. }
  616. esp_err_t handler_rssi(httpd_req_t *req)
  617. {
  618. #ifdef DEBUG_DETAIL_ON
  619. LogFile.WriteHeapInfo("handler_rssi - Start");
  620. #endif
  621. if (getWIFIisConnected())
  622. {
  623. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  624. httpd_resp_send(req, std::to_string(get_WIFI_RSSI()).c_str(), HTTPD_RESP_USE_STRLEN);
  625. }
  626. else
  627. {
  628. httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "WIFI not (yet) connected: REST API /rssi not available!");
  629. return ESP_ERR_NOT_FOUND;
  630. }
  631. #ifdef DEBUG_DETAIL_ON
  632. LogFile.WriteHeapInfo("handler_rssi - End");
  633. #endif
  634. return ESP_OK;
  635. }
  636. esp_err_t handler_uptime(httpd_req_t *req)
  637. {
  638. #ifdef DEBUG_DETAIL_ON
  639. LogFile.WriteHeapInfo("handler_uptime - Start");
  640. #endif
  641. std::string formatedUptime = getFormatedUptime(false);
  642. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  643. httpd_resp_send(req, formatedUptime.c_str(), formatedUptime.length());
  644. #ifdef DEBUG_DETAIL_ON
  645. LogFile.WriteHeapInfo("handler_uptime - End");
  646. #endif
  647. return ESP_OK;
  648. }
  649. esp_err_t handler_prevalue(httpd_req_t *req)
  650. {
  651. #ifdef DEBUG_DETAIL_ON
  652. LogFile.WriteHeapInfo("handler_prevalue - Start");
  653. ESP_LOGD(TAG, "handler_prevalue: %s", req->uri);
  654. #endif
  655. // Default usage message when handler gets called without any parameter
  656. const std::string RESTUsageInfo =
  657. "00: Handler usage:<br>"
  658. "- To retrieve actual PreValue, please provide only a numbersname, e.g. /setPreValue?numbers=main<br>"
  659. "- To set PreValue to a new value, please provide a numbersname and a value, e.g. /setPreValue?numbers=main&value=1234.5678<br>"
  660. "NOTE:<br>"
  661. "value >= 0.0: Set PreValue to provided value<br>"
  662. "value < 0.0: Set PreValue to actual RAW value (as long RAW value is a valid number, without N)";
  663. // Default return error message when no return is programmed
  664. std::string sReturnMessage = "E90: Uninitialized";
  665. char _query[100];
  666. char _numbersname[50] = "default";
  667. char _value[20] = "";
  668. httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  669. if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) {
  670. #ifdef DEBUG_DETAIL_ON
  671. ESP_LOGD(TAG, "Query: %s", _query);
  672. #endif
  673. if (httpd_query_key_value(_query, "numbers", _numbersname, 50) != ESP_OK) { // If request is incomplete
  674. sReturnMessage = "E91: Query parameter incomplete or not valid!<br> "
  675. "Call /setPreValue to show REST API usage info and/or check documentation";
  676. httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
  677. return ESP_FAIL;
  678. }
  679. if (httpd_query_key_value(_query, "value", _value, 20) == ESP_OK) {
  680. #ifdef DEBUG_DETAIL_ON
  681. ESP_LOGD(TAG, "Value: %s", _size);
  682. #endif
  683. }
  684. }
  685. else { // if no parameter is provided, print handler usage
  686. httpd_resp_send(req, RESTUsageInfo.c_str(), RESTUsageInfo.length());
  687. return ESP_OK;
  688. }
  689. if (strlen(_value) == 0) { // If no value is povided --> return actual PreValue
  690. sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname));
  691. if (sReturnMessage.empty()) {
  692. sReturnMessage = "E92: Numbers name not found";
  693. httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
  694. return ESP_FAIL;
  695. }
  696. }
  697. else {
  698. // New value is positive: Set PreValue to provided value and return value
  699. // New value is negative and actual RAW value is a valid number: Set PreValue to RAW value and return value
  700. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "REST API handler_prevalue called: numbersname: " + std::string(_numbersname) +
  701. ", value: " + std::string(_value));
  702. if (!flowctrl.UpdatePrevalue(_value, _numbersname, true)) {
  703. sReturnMessage = "E93: Update request rejected. Please check device logs for more details";
  704. httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
  705. return ESP_FAIL;
  706. }
  707. sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname));
  708. if (sReturnMessage.empty()) {
  709. sReturnMessage = "E94: Numbers name not found";
  710. httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
  711. return ESP_FAIL;
  712. }
  713. }
  714. httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
  715. #ifdef DEBUG_DETAIL_ON
  716. LogFile.WriteHeapInfo("handler_prevalue - End");
  717. #endif
  718. return ESP_OK;
  719. }
  720. void task_autodoFlow(void *pvParameter)
  721. {
  722. int64_t fr_start, fr_delta_ms;
  723. bTaskAutoFlowCreated = true;
  724. if (!isPlannedReboot && (esp_reset_reason() == ESP_RST_PANIC))
  725. {
  726. flowctrl.setActStatus("Initialization (delayed)");
  727. //#ifdef ENABLE_MQTT
  728. //MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization (delayed)", false); // Right now, not possible -> MQTT Service is going to be started later
  729. //#endif //ENABLE_MQTT
  730. vTaskDelay(60*5000 / portTICK_PERIOD_MS); // Wait 5 minutes to give time to do an OTA update or fetch the log
  731. }
  732. ESP_LOGD(TAG, "task_autodoFlow: start");
  733. doInit();
  734. auto_isrunning = flowctrl.isAutoStart(auto_interval);
  735. if (isSetupModusActive())
  736. {
  737. auto_isrunning = false;
  738. std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT);
  739. flowctrl.doFlowTakeImageOnly(zw_time);
  740. }
  741. while (auto_isrunning)
  742. {
  743. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "----------------------------------------------------------------"); // Clear separation between runs
  744. std::string _zw = "Round #" + std::to_string(++countRounds) + " started";
  745. time_t roundStartTime = getUpTime();
  746. LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw);
  747. fr_start = esp_timer_get_time();
  748. if (flowisrunning)
  749. {
  750. #ifdef DEBUG_DETAIL_ON
  751. ESP_LOGD(TAG, "Autoflow: doFlow is already running!");
  752. #endif
  753. }
  754. else
  755. {
  756. #ifdef DEBUG_DETAIL_ON
  757. ESP_LOGD(TAG, "Autoflow: doFlow is started");
  758. #endif
  759. flowisrunning = true;
  760. doflow();
  761. #ifdef DEBUG_DETAIL_ON
  762. ESP_LOGD(TAG, "Remove older log files");
  763. #endif
  764. LogFile.RemoveOldLogFile();
  765. LogFile.RemoveOldDataLog();
  766. }
  767. // Round finished -> Logfile
  768. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Round #" + std::to_string(countRounds) +
  769. " completed (" + std::to_string(getUpTime() - roundStartTime) + " seconds)");
  770. // CPU Temp -> Logfile
  771. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CPU Temperature: " + std::to_string((int)temperatureRead()) + "°C");
  772. // WIFI Signal Strength (RSSI) -> Logfile
  773. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "WIFI Signal (RSSI): " + std::to_string(get_WIFI_RSSI()) + "dBm");
  774. // Check if time is synchronized (if NTP is configured)
  775. if (getUseNtp() && !getTimeIsSet()) {
  776. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Time server is configured, but time is not yet set!");
  777. StatusLED(TIME_CHECK, 1, false);
  778. }
  779. #if (defined WLAN_USE_MESH_ROAMING && defined WLAN_USE_MESH_ROAMING_ACTIVATE_CLIENT_TRIGGERED_QUERIES)
  780. wifiRoamingQuery();
  781. #endif
  782. // Scan channels and check if an AP with better RSSI is available, then disconnect and try to reconnect to AP with better RSSI
  783. // NOTE: Keep this direct before the following task delay, because scan is done in blocking mode and this takes ca. 1,5 - 2s.
  784. #ifdef WLAN_USE_ROAMING_BY_SCANNING
  785. wifiRoamByScanning();
  786. #endif
  787. fr_delta_ms = (esp_timer_get_time() - fr_start) / 1000;
  788. if (auto_interval > fr_delta_ms)
  789. {
  790. const TickType_t xDelay = (auto_interval - fr_delta_ms) / portTICK_PERIOD_MS;
  791. ESP_LOGD(TAG, "Autoflow: sleep for: %ldms", (long) xDelay);
  792. vTaskDelay( xDelay );
  793. }
  794. }
  795. vTaskDelete(NULL); //Delete this task if it exits from the loop above
  796. xHandletask_autodoFlow = NULL;
  797. ESP_LOGD(TAG, "task_autodoFlow: end");
  798. }
  799. void StartMainFlowTask()
  800. {
  801. BaseType_t xReturned;
  802. ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str());
  803. uint32_t stackSize = 16 * 1024;
  804. xReturned = xTaskCreatePinnedToCore(&task_autodoFlow, "task_autodoFlow", stackSize, NULL, tskIDLE_PRIORITY+2, &xHandletask_autodoFlow, 0);
  805. if( xReturned != pdPASS )
  806. {
  807. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Creation task_autodoFlow failed. Requested stack size:" + std::to_string(stackSize));
  808. LogFile.WriteHeapInfo("Creation task_autodoFlow failed");
  809. }
  810. ESP_LOGD(TAG, "getESPHeapInfo: %s", getESPHeapInfo().c_str());
  811. }
  812. void register_server_main_flow_task_uri(httpd_handle_t server)
  813. {
  814. ESP_LOGI(TAG, "server_main_flow_task - Registering URI handlers");
  815. httpd_uri_t camuri = { };
  816. camuri.method = HTTP_GET;
  817. camuri.uri = "/doinit";
  818. camuri.handler = handler_init;
  819. camuri.user_ctx = (void*) "Light On";
  820. httpd_register_uri_handler(server, &camuri);
  821. // Legacy API => New: "/setPreValue"
  822. camuri.uri = "/setPreValue.html";
  823. camuri.handler = handler_prevalue;
  824. camuri.user_ctx = (void*) "Prevalue";
  825. httpd_register_uri_handler(server, &camuri);
  826. camuri.uri = "/setPreValue";
  827. camuri.handler = handler_prevalue;
  828. camuri.user_ctx = (void*) "Prevalue";
  829. httpd_register_uri_handler(server, &camuri);
  830. camuri.uri = "/flow_start";
  831. camuri.handler = handler_flow_start;
  832. camuri.user_ctx = (void*) "Flow Start";
  833. httpd_register_uri_handler(server, &camuri);
  834. camuri.uri = "/statusflow.html";
  835. camuri.handler = handler_statusflow;
  836. camuri.user_ctx = (void*) "Light Off";
  837. httpd_register_uri_handler(server, &camuri);
  838. camuri.uri = "/statusflow";
  839. camuri.handler = handler_statusflow;
  840. camuri.user_ctx = (void*) "Light Off";
  841. httpd_register_uri_handler(server, &camuri);
  842. // Legacy API => New: "/cpu_temperature"
  843. camuri.uri = "/cputemp.html";
  844. camuri.handler = handler_cputemp;
  845. camuri.user_ctx = (void*) "Light Off";
  846. httpd_register_uri_handler(server, &camuri);
  847. camuri.uri = "/cpu_temperature";
  848. camuri.handler = handler_cputemp;
  849. camuri.user_ctx = (void*) "Light Off";
  850. httpd_register_uri_handler(server, &camuri);
  851. // Legacy API => New: "/rssi"
  852. camuri.uri = "/rssi.html";
  853. camuri.handler = handler_rssi;
  854. camuri.user_ctx = (void*) "Light Off";
  855. httpd_register_uri_handler(server, &camuri);
  856. camuri.uri = "/rssi";
  857. camuri.handler = handler_rssi;
  858. camuri.user_ctx = (void*) "Light Off";
  859. httpd_register_uri_handler(server, &camuri);
  860. camuri.uri = "/uptime";
  861. camuri.handler = handler_uptime;
  862. camuri.user_ctx = (void*) "Light Off";
  863. httpd_register_uri_handler(server, &camuri);
  864. camuri.uri = "/editflow";
  865. camuri.handler = handler_editflow;
  866. camuri.user_ctx = (void*) "EditFlow";
  867. httpd_register_uri_handler(server, &camuri);
  868. // Legacy API => New: "/value"
  869. camuri.uri = "/value.html";
  870. camuri.handler = handler_wasserzaehler;
  871. camuri.user_ctx = (void*) "Value";
  872. httpd_register_uri_handler(server, &camuri);
  873. camuri.uri = "/value";
  874. camuri.handler = handler_wasserzaehler;
  875. camuri.user_ctx = (void*) "Value";
  876. httpd_register_uri_handler(server, &camuri);
  877. // Legacy API => New: "/value"
  878. camuri.uri = "/wasserzaehler.html";
  879. camuri.handler = handler_wasserzaehler;
  880. camuri.user_ctx = (void*) "Wasserzaehler";
  881. httpd_register_uri_handler(server, &camuri);
  882. camuri.uri = "/json";
  883. camuri.handler = handler_json;
  884. camuri.user_ctx = (void*) "JSON";
  885. httpd_register_uri_handler(server, &camuri);
  886. camuri.uri = "/heap";
  887. camuri.handler = handler_get_heap;
  888. camuri.user_ctx = (void*) "Heap";
  889. httpd_register_uri_handler(server, &camuri);
  890. camuri.uri = "/stream";
  891. camuri.handler = handler_stream;
  892. camuri.user_ctx = (void*) "stream";
  893. httpd_register_uri_handler(server, &camuri);
  894. }