ClassFlowPostProcessing.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290
  1. #include "ClassFlowPostProcessing.h"
  2. #include "Helper.h"
  3. #include "ClassFlowTakeImage.h"
  4. #include "ClassLogFile.h"
  5. #include <iomanip>
  6. #include <sstream>
  7. #include <cassert>
  8. #include <time.h>
  9. #include "time_sntp.h"
  10. #include "esp_log.h"
  11. #include "../../include/defines.h"
  12. static const char* TAG = "POSTPROC";
  13. std::string ClassFlowPostProcessing::getNumbersName()
  14. {
  15. std::string ret="";
  16. for (int i = 0; i < NUMBERS.size(); ++i)
  17. {
  18. ret += NUMBERS[i]->name;
  19. if (i < NUMBERS.size()-1)
  20. ret = ret + "\t";
  21. }
  22. // ESP_LOGI(TAG, "Result ClassFlowPostProcessing::getNumbersName: %s", ret.c_str());
  23. return ret;
  24. }
  25. std::string ClassFlowPostProcessing::GetJSON(std::string _lineend)
  26. {
  27. std::string json="{" + _lineend;
  28. for (int i = 0; i < NUMBERS.size(); ++i)
  29. {
  30. json += "\"" + NUMBERS[i]->name + "\":" + _lineend;
  31. json += getJsonFromNumber(i, _lineend) + _lineend;
  32. if ((i+1) < NUMBERS.size())
  33. json += "," + _lineend;
  34. }
  35. json += "}";
  36. return json;
  37. }
  38. string ClassFlowPostProcessing::getJsonFromNumber(int i, std::string _lineend) {
  39. std::string json = "";
  40. json += " {" + _lineend;
  41. if (NUMBERS[i]->ReturnValue.length() > 0)
  42. json += " \"value\": \"" + NUMBERS[i]->ReturnValue + "\"," + _lineend;
  43. else
  44. json += " \"value\": \"\"," + _lineend;
  45. json += " \"raw\": \"" + NUMBERS[i]->ReturnRawValue + "\"," + _lineend;
  46. json += " \"pre\": \"" + NUMBERS[i]->ReturnPreValue + "\"," + _lineend;
  47. json += " \"error\": \"" + NUMBERS[i]->ErrorMessageText + "\"," + _lineend;
  48. if (NUMBERS[i]->ReturnRateValue.length() > 0)
  49. json += " \"rate\": \"" + NUMBERS[i]->ReturnRateValue + "\"," + _lineend;
  50. else
  51. json += " \"rate\": \"\"," + _lineend;
  52. json += " \"timestamp\": \"" + NUMBERS[i]->timeStamp + "\"" + _lineend;
  53. json += " }" + _lineend;
  54. return json;
  55. }
  56. string ClassFlowPostProcessing::GetPreValue(std::string _number)
  57. {
  58. std::string result;
  59. int index = -1;
  60. if (_number == "")
  61. _number = "default";
  62. for (int i = 0; i < NUMBERS.size(); ++i)
  63. if (NUMBERS[i]->name == _number)
  64. index = i;
  65. if (index == -1)
  66. return std::string("");
  67. result = RundeOutput(NUMBERS[index]->PreValue, NUMBERS[index]->Nachkomma);
  68. return result;
  69. }
  70. bool ClassFlowPostProcessing::SetPreValue(double _newvalue, string _numbers, bool _extern)
  71. {
  72. //ESP_LOGD(TAG, "SetPrevalue: %f, %s", zw, _numbers.c_str());
  73. for (int j = 0; j < NUMBERS.size(); ++j) {
  74. //ESP_LOGD(TAG, "Number %d, %s", j, NUMBERS[j]->name.c_str());
  75. if (NUMBERS[j]->name == _numbers) {
  76. if (_newvalue >= 0) { // if new value posivive, use provided value to preset PreValue
  77. NUMBERS[j]->PreValue = _newvalue;
  78. }
  79. else { // if new value negative, use last raw value to preset PreValue
  80. char* p;
  81. double ReturnRawValueAsDouble = strtod(NUMBERS[j]->ReturnRawValue.c_str(), &p);
  82. if (ReturnRawValueAsDouble == 0) {
  83. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "SetPreValue: RawValue not a valid value for further processing: "
  84. + NUMBERS[j]->ReturnRawValue);
  85. return false;
  86. }
  87. NUMBERS[j]->PreValue = ReturnRawValueAsDouble;
  88. }
  89. NUMBERS[j]->ReturnPreValue = std::to_string(NUMBERS[j]->PreValue);
  90. NUMBERS[j]->PreValueOkay = true;
  91. if (_extern)
  92. {
  93. time(&(NUMBERS[j]->lastvalue));
  94. localtime(&(NUMBERS[j]->lastvalue));
  95. }
  96. //ESP_LOGD(TAG, "Found %d! - set to %.8f", j, NUMBERS[j]->PreValue);
  97. UpdatePreValueINI = true; // Only update prevalue file if a new value is set
  98. SavePreValue();
  99. LogFile.WriteToFile(ESP_LOG_INFO, TAG, "SetPreValue: PreValue for " + NUMBERS[j]->name + " set to " +
  100. std::to_string(NUMBERS[j]->PreValue));
  101. return true;
  102. }
  103. }
  104. LogFile.WriteToFile(ESP_LOG_WARN, TAG, "SetPreValue: Numbersname not found or not valid");
  105. return false; // No new value was set (e.g. wrong numbersname, no numbers at all)
  106. }
  107. bool ClassFlowPostProcessing::LoadPreValue(void)
  108. {
  109. std::vector<string> splitted;
  110. FILE* pFile;
  111. char zw[1024];
  112. string zwtime, zwvalue, name;
  113. bool _done = false;
  114. UpdatePreValueINI = false; // Conversion to the new format
  115. pFile = fopen(FilePreValue.c_str(), "r");
  116. if (pFile == NULL)
  117. return false;
  118. fgets(zw, 1024, pFile);
  119. ESP_LOGD(TAG, "Read line Prevalue.ini: %s", zw);
  120. zwtime = trim(std::string(zw));
  121. if (zwtime.length() == 0)
  122. return false;
  123. splitted = HelperZerlegeZeile(zwtime, "\t");
  124. if (splitted.size() > 1) // Conversion to the new format
  125. {
  126. while ((splitted.size() > 1) && !_done)
  127. {
  128. name = trim(splitted[0]);
  129. zwtime = trim(splitted[1]);
  130. zwvalue = trim(splitted[2]);
  131. for (int j = 0; j < NUMBERS.size(); ++j)
  132. {
  133. if (NUMBERS[j]->name == name)
  134. {
  135. NUMBERS[j]->PreValue = stod(zwvalue.c_str());
  136. NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma + 1); // To be on the safe side, 1 digit more, as Exgtended Resolution may be on (will only be set during the first run).
  137. time_t tStart;
  138. int yy, month, dd, hh, mm, ss;
  139. struct tm whenStart;
  140. sscanf(zwtime.c_str(), PREVALUE_TIME_FORMAT_INPUT, &yy, &month, &dd, &hh, &mm, &ss);
  141. whenStart.tm_year = yy - 1900;
  142. whenStart.tm_mon = month - 1;
  143. whenStart.tm_mday = dd;
  144. whenStart.tm_hour = hh;
  145. whenStart.tm_min = mm;
  146. whenStart.tm_sec = ss;
  147. whenStart.tm_isdst = -1;
  148. NUMBERS[j]->lastvalue = mktime(&whenStart);
  149. time(&tStart);
  150. localtime(&tStart);
  151. double difference = difftime(tStart, NUMBERS[j]->lastvalue);
  152. difference /= 60;
  153. if (difference > PreValueAgeStartup)
  154. NUMBERS[j]->PreValueOkay = false;
  155. else
  156. NUMBERS[j]->PreValueOkay = true;
  157. }
  158. }
  159. if (!fgets(zw, 1024, pFile))
  160. _done = true;
  161. else
  162. {
  163. ESP_LOGD(TAG, "Read line Prevalue.ini: %s", zw);
  164. splitted = HelperZerlegeZeile(trim(std::string(zw)), "\t");
  165. if (splitted.size() > 1)
  166. {
  167. name = trim(splitted[0]);
  168. zwtime = trim(splitted[1]);
  169. zwvalue = trim(splitted[2]);
  170. }
  171. }
  172. }
  173. fclose(pFile);
  174. }
  175. else // Old Format
  176. {
  177. fgets(zw, 1024, pFile);
  178. fclose(pFile);
  179. ESP_LOGD(TAG, "%s", zw);
  180. zwvalue = trim(std::string(zw));
  181. NUMBERS[0]->PreValue = stod(zwvalue.c_str());
  182. time_t tStart;
  183. int yy, month, dd, hh, mm, ss;
  184. struct tm whenStart;
  185. sscanf(zwtime.c_str(), PREVALUE_TIME_FORMAT_INPUT, &yy, &month, &dd, &hh, &mm, &ss);
  186. whenStart.tm_year = yy - 1900;
  187. whenStart.tm_mon = month - 1;
  188. whenStart.tm_mday = dd;
  189. whenStart.tm_hour = hh;
  190. whenStart.tm_min = mm;
  191. whenStart.tm_sec = ss;
  192. whenStart.tm_isdst = -1;
  193. ESP_LOGD(TAG, "TIME: %d, %d, %d, %d, %d, %d", whenStart.tm_year, whenStart.tm_mon, whenStart.tm_wday, whenStart.tm_hour, whenStart.tm_min, whenStart.tm_sec);
  194. NUMBERS[0]->lastvalue = mktime(&whenStart);
  195. time(&tStart);
  196. localtime(&tStart);
  197. double difference = difftime(tStart, NUMBERS[0]->lastvalue);
  198. difference /= 60;
  199. if (difference > PreValueAgeStartup)
  200. return false;
  201. NUMBERS[0]->Value = NUMBERS[0]->PreValue;
  202. NUMBERS[0]->ReturnValue = to_string(NUMBERS[0]->Value);
  203. if (NUMBERS[0]->digit_roi || NUMBERS[0]->analog_roi)
  204. {
  205. NUMBERS[0]->ReturnValue = RundeOutput(NUMBERS[0]->Value, NUMBERS[0]->Nachkomma);
  206. }
  207. UpdatePreValueINI = true; // Conversion to the new format
  208. SavePreValue();
  209. }
  210. return true;
  211. }
  212. void ClassFlowPostProcessing::SavePreValue()
  213. {
  214. FILE* pFile;
  215. string _zw;
  216. if (!UpdatePreValueINI) // PreValues unchanged --> File does not have to be rewritten
  217. return;
  218. pFile = fopen(FilePreValue.c_str(), "w");
  219. for (int j = 0; j < NUMBERS.size(); ++j)
  220. {
  221. char buffer[80];
  222. struct tm* timeinfo = localtime(&NUMBERS[j]->lastvalue);
  223. strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
  224. NUMBERS[j]->timeStamp = std::string(buffer);
  225. // ESP_LOGD(TAG, "SaverPreValue %d, Value: %f, Nachkomma %d", j, NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
  226. _zw = NUMBERS[j]->name + "\t" + NUMBERS[j]->timeStamp + "\t" + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + "\n";
  227. ESP_LOGD(TAG, "Write PreValue line: %s", _zw.c_str());
  228. if (pFile) {
  229. fputs(_zw.c_str(), pFile);
  230. }
  231. }
  232. UpdatePreValueINI = false;
  233. fclose(pFile);
  234. }
  235. ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc, ClassFlowCNNGeneral *_analog, ClassFlowCNNGeneral *_digit)
  236. {
  237. PreValueUse = false;
  238. PreValueAgeStartup = 30;
  239. ErrorMessage = false;
  240. ListFlowControll = NULL;
  241. FilePreValue = FormatFileName("/sdcard/config/prevalue.ini");
  242. ListFlowControll = lfc;
  243. flowTakeImage = NULL;
  244. UpdatePreValueINI = false;
  245. IgnoreLeadingNaN = false;
  246. flowAnalog = _analog;
  247. flowDigit = _digit;
  248. for (int i = 0; i < ListFlowControll->size(); ++i)
  249. {
  250. if (((*ListFlowControll)[i])->name().compare("ClassFlowTakeImage") == 0)
  251. {
  252. flowTakeImage = (ClassFlowTakeImage*) (*ListFlowControll)[i];
  253. }
  254. }
  255. }
  256. void ClassFlowPostProcessing::handleDecimalExtendedResolution(string _decsep, string _value)
  257. {
  258. string _digit, _decpos;
  259. int _pospunkt = _decsep.find_first_of(".");
  260. // ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
  261. if (_pospunkt > -1)
  262. _digit = _decsep.substr(0, _pospunkt);
  263. else
  264. _digit = "default";
  265. for (int j = 0; j < NUMBERS.size(); ++j)
  266. {
  267. bool _zwdc = false;
  268. if (toUpper(_value) == "TRUE")
  269. _zwdc = true;
  270. if (_digit == "default") // Set to default first (if nothing else is set)
  271. {
  272. NUMBERS[j]->isExtendedResolution = _zwdc;
  273. }
  274. if (NUMBERS[j]->name == _digit)
  275. {
  276. NUMBERS[j]->isExtendedResolution = _zwdc;
  277. }
  278. }
  279. }
  280. void ClassFlowPostProcessing::handleDecimalSeparator(string _decsep, string _value)
  281. {
  282. string _digit, _decpos;
  283. int _pospunkt = _decsep.find_first_of(".");
  284. // ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
  285. if (_pospunkt > -1)
  286. _digit = _decsep.substr(0, _pospunkt);
  287. else
  288. _digit = "default";
  289. for (int j = 0; j < NUMBERS.size(); ++j)
  290. {
  291. int _zwdc = 0;
  292. // try
  293. {
  294. _zwdc = stoi(_value);
  295. }
  296. /* catch(const std::exception& e)
  297. {
  298. ESP_LOGD(TAG, "ERROR - Decimalshift is not a number: %s", _value.c_str());
  299. }
  300. */
  301. if (_digit == "default") // Set to default first (if nothing else is set)
  302. {
  303. NUMBERS[j]->DecimalShift = _zwdc;
  304. NUMBERS[j]->DecimalShiftInitial = _zwdc;
  305. }
  306. if (NUMBERS[j]->name == _digit)
  307. {
  308. NUMBERS[j]->DecimalShift = _zwdc;
  309. NUMBERS[j]->DecimalShiftInitial = _zwdc;
  310. }
  311. NUMBERS[j]->Nachkomma = NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift;
  312. }
  313. }
  314. void ClassFlowPostProcessing::handleAnalogDigitalTransitionStart(string _decsep, string _value)
  315. {
  316. string _digit, _decpos;
  317. int _pospunkt = _decsep.find_first_of(".");
  318. // ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
  319. if (_pospunkt > -1)
  320. _digit = _decsep.substr(0, _pospunkt);
  321. else
  322. _digit = "default";
  323. for (int j = 0; j < NUMBERS.size(); ++j)
  324. {
  325. float _zwdc = 9.2;
  326. {
  327. _zwdc = stof(_value);
  328. }
  329. if (_digit == "default" || NUMBERS[j]->name == _digit) // Set to default first (if nothing else is set)
  330. {
  331. NUMBERS[j]->AnalogDigitalTransitionStart = _zwdc;
  332. }
  333. }
  334. }
  335. void ClassFlowPostProcessing::handleAllowNegativeRate(string _decsep, string _value)
  336. {
  337. string _digit, _decpos;
  338. int _pospunkt = _decsep.find_first_of(".");
  339. // ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
  340. if (_pospunkt > -1)
  341. _digit = _decsep.substr(0, _pospunkt);
  342. else
  343. _digit = "default";
  344. for (int j = 0; j < NUMBERS.size(); ++j)
  345. {
  346. bool _rt = false;
  347. if (toUpper(_value) == "TRUE")
  348. _rt = true;
  349. if (_digit == "default") // Set to default first (if nothing else is set)
  350. {
  351. NUMBERS[j]->AllowNegativeRates = _rt;
  352. }
  353. if (NUMBERS[j]->name == _digit)
  354. {
  355. NUMBERS[j]->AllowNegativeRates = _rt;
  356. }
  357. }
  358. }
  359. void ClassFlowPostProcessing::handleMaxRateType(string _decsep, string _value)
  360. {
  361. string _digit, _decpos;
  362. int _pospunkt = _decsep.find_first_of(".");
  363. // ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
  364. if (_pospunkt > -1)
  365. _digit = _decsep.substr(0, _pospunkt);
  366. else
  367. _digit = "default";
  368. for (int j = 0; j < NUMBERS.size(); ++j)
  369. {
  370. t_RateType _rt = AbsoluteChange;
  371. if (toUpper(_value) == "RATECHANGE")
  372. _rt = RateChange;
  373. if (_digit == "default") // Set to default first (if nothing else is set)
  374. {
  375. NUMBERS[j]->RateType = _rt;
  376. }
  377. if (NUMBERS[j]->name == _digit)
  378. {
  379. NUMBERS[j]->RateType = _rt;
  380. }
  381. }
  382. }
  383. void ClassFlowPostProcessing::handleMaxRateValue(string _decsep, string _value)
  384. {
  385. string _digit, _decpos;
  386. int _pospunkt = _decsep.find_first_of(".");
  387. // ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
  388. if (_pospunkt > -1)
  389. _digit = _decsep.substr(0, _pospunkt);
  390. else
  391. _digit = "default";
  392. for (int j = 0; j < NUMBERS.size(); ++j)
  393. {
  394. float _zwdc = 1;
  395. // try
  396. {
  397. _zwdc = stof(_value);
  398. }
  399. /* catch(const std::exception& e)
  400. {
  401. ESP_LOGD(TAG, "ERROR - MaxRateValue is not a number: %s", _value.c_str());
  402. }
  403. */
  404. if (_digit == "default") // Set to default first (if nothing else is set)
  405. {
  406. NUMBERS[j]->useMaxRateValue = true;
  407. NUMBERS[j]->MaxRateValue = _zwdc;
  408. }
  409. if (NUMBERS[j]->name == _digit)
  410. {
  411. NUMBERS[j]->useMaxRateValue = true;
  412. NUMBERS[j]->MaxRateValue = _zwdc;
  413. }
  414. }
  415. }
  416. bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph)
  417. {
  418. std::vector<string> splitted;
  419. int _n;
  420. aktparamgraph = trim(aktparamgraph);
  421. if (aktparamgraph.size() == 0)
  422. if (!this->GetNextParagraph(pfile, aktparamgraph))
  423. return false;
  424. if (aktparamgraph.compare("[PostProcessing]") != 0) // Paragraph does not fit PostProcessing
  425. return false;
  426. InitNUMBERS();
  427. while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
  428. {
  429. splitted = ZerlegeZeile(aktparamgraph);
  430. std::string _param = GetParameterName(splitted[0]);
  431. if ((toUpper(_param) == "EXTENDEDRESOLUTION") && (splitted.size() > 1))
  432. {
  433. handleDecimalExtendedResolution(splitted[0], splitted[1]);
  434. }
  435. if ((toUpper(_param) == "DECIMALSHIFT") && (splitted.size() > 1))
  436. {
  437. handleDecimalSeparator(splitted[0], splitted[1]);
  438. }
  439. if ((toUpper(_param) == "ANALOGDIGITALTRANSITIONSTART") && (splitted.size() > 1))
  440. {
  441. handleAnalogDigitalTransitionStart(splitted[0], splitted[1]);
  442. }
  443. if ((toUpper(_param) == "MAXRATEVALUE") && (splitted.size() > 1))
  444. {
  445. handleMaxRateValue(splitted[0], splitted[1]);
  446. }
  447. if ((toUpper(_param) == "MAXRATETYPE") && (splitted.size() > 1))
  448. {
  449. handleMaxRateType(splitted[0], splitted[1]);
  450. }
  451. if ((toUpper(_param) == "PREVALUEUSE") && (splitted.size() > 1))
  452. {
  453. if (toUpper(splitted[1]) == "TRUE")
  454. {
  455. PreValueUse = true;
  456. }
  457. }
  458. if ((toUpper(_param) == "CHECKDIGITINCREASECONSISTENCY") && (splitted.size() > 1))
  459. {
  460. if (toUpper(splitted[1]) == "TRUE")
  461. for (_n = 0; _n < NUMBERS.size(); ++_n)
  462. NUMBERS[_n]->checkDigitIncreaseConsistency = true;
  463. }
  464. if ((toUpper(_param) == "ALLOWNEGATIVERATES") && (splitted.size() > 1))
  465. {
  466. handleAllowNegativeRate(splitted[0], splitted[1]);
  467. /* Updated to allow individual Settings
  468. if (toUpper(splitted[1]) == "TRUE")
  469. for (_n = 0; _n < NUMBERS.size(); ++_n)
  470. NUMBERS[_n]->AllowNegativeRates = true;
  471. */
  472. }
  473. if ((toUpper(_param) == "ERRORMESSAGE") && (splitted.size() > 1))
  474. {
  475. if (toUpper(splitted[1]) == "TRUE")
  476. ErrorMessage = true;
  477. }
  478. if ((toUpper(_param) == "IGNORELEADINGNAN") && (splitted.size() > 1))
  479. {
  480. if (toUpper(splitted[1]) == "TRUE")
  481. IgnoreLeadingNaN = true;
  482. }
  483. if ((toUpper(_param) == "PREVALUEAGESTARTUP") && (splitted.size() > 1))
  484. {
  485. PreValueAgeStartup = std::stoi(splitted[1]);
  486. }
  487. }
  488. if (PreValueUse) {
  489. LoadPreValue();
  490. }
  491. return true;
  492. }
  493. void ClassFlowPostProcessing::InitNUMBERS()
  494. {
  495. int anzDIGIT = 0;
  496. int anzANALOG = 0;
  497. std::vector<std::string> name_numbers;
  498. if (flowDigit)
  499. {
  500. anzDIGIT = flowDigit->getNumberGENERAL();
  501. flowDigit->UpdateNameNumbers(&name_numbers);
  502. }
  503. if (flowAnalog)
  504. {
  505. anzANALOG = flowAnalog->getNumberGENERAL();
  506. flowAnalog->UpdateNameNumbers(&name_numbers);
  507. }
  508. ESP_LOGD(TAG, "Anzahl NUMBERS: %d - DIGITS: %d, ANALOG: %d", name_numbers.size(), anzDIGIT, anzANALOG);
  509. for (int _num = 0; _num < name_numbers.size(); ++_num)
  510. {
  511. NumberPost *_number = new NumberPost;
  512. _number->name = name_numbers[_num];
  513. _number->digit_roi = NULL;
  514. if (flowDigit)
  515. _number->digit_roi = flowDigit->FindGENERAL(name_numbers[_num]);
  516. if (_number->digit_roi)
  517. _number->AnzahlDigital = _number->digit_roi->ROI.size();
  518. else
  519. _number->AnzahlDigital = 0;
  520. _number->analog_roi = NULL;
  521. if (flowAnalog)
  522. _number->analog_roi = flowAnalog->FindGENERAL(name_numbers[_num]);
  523. if (_number->analog_roi)
  524. _number->AnzahlAnalog = _number->analog_roi->ROI.size();
  525. else
  526. _number->AnzahlAnalog = 0;
  527. _number->ReturnRawValue = ""; // Raw value (with N & leading 0).
  528. _number->ReturnValue = ""; // corrected return value, possibly with error message
  529. _number->ErrorMessageText = ""; // Error message for consistency check
  530. _number->ReturnPreValue = "";
  531. _number->PreValueOkay = false;
  532. _number->AllowNegativeRates = false;
  533. _number->MaxRateValue = 0.1;
  534. _number->RateType = AbsoluteChange;
  535. _number->useMaxRateValue = false;
  536. _number->checkDigitIncreaseConsistency = false;
  537. _number->DecimalShift = 0;
  538. _number->DecimalShiftInitial = 0;
  539. _number->isExtendedResolution = false;
  540. _number->AnalogDigitalTransitionStart=9.2;
  541. _number->FlowRateAct = 0; // m3 / min
  542. _number->PreValue = 0; // last value read out well
  543. _number->Value = 0; // last value read out, incl. corrections
  544. _number->ReturnRawValue = ""; // raw value (with N & leading 0)
  545. _number->ReturnValue = ""; // corrected return value, possibly with error message
  546. _number->ErrorMessageText = ""; // Error message for consistency check
  547. _number->Nachkomma = _number->AnzahlAnalog;
  548. NUMBERS.push_back(_number);
  549. }
  550. for (int i = 0; i < NUMBERS.size(); ++i) {
  551. ESP_LOGD(TAG, "Number %s, Anz DIG: %d, Anz ANA %d", NUMBERS[i]->name.c_str(), NUMBERS[i]->AnzahlDigital, NUMBERS[i]->AnzahlAnalog);
  552. }
  553. }
  554. string ClassFlowPostProcessing::ShiftDecimal(string in, int _decShift){
  555. if (_decShift == 0){
  556. return in;
  557. }
  558. int _pos_dec_org, _pos_dec_neu;
  559. _pos_dec_org = findDelimiterPos(in, ".");
  560. if (_pos_dec_org == std::string::npos) {
  561. _pos_dec_org = in.length();
  562. }
  563. else
  564. {
  565. in = in.erase(_pos_dec_org, 1);
  566. }
  567. _pos_dec_neu = _pos_dec_org + _decShift;
  568. if (_pos_dec_neu <= 0) { // comma is before the first digit
  569. for (int i = 0; i > _pos_dec_neu; --i){
  570. in = in.insert(0, "0");
  571. }
  572. in = "0." + in;
  573. return in;
  574. }
  575. if (_pos_dec_neu > in.length()){ // Comma should be after string (123 --> 1230)
  576. for (int i = in.length(); i < _pos_dec_neu; ++i){
  577. in = in.insert(in.length(), "0");
  578. }
  579. return in;
  580. }
  581. string zw;
  582. zw = in.substr(0, _pos_dec_neu);
  583. zw = zw + ".";
  584. zw = zw + in.substr(_pos_dec_neu, in.length() - _pos_dec_neu);
  585. return zw;
  586. }
  587. float wrapAround(float val)
  588. {
  589. return fmod(val, 10.);
  590. }
  591. /**
  592. * @brief Checks whether val is in the range [min, max]
  593. *
  594. * Note, this function also handles the wrap around case,
  595. * in which min could be larger than max in case of
  596. * a circular range
  597. *
  598. * @param val The value to be checked
  599. * @param min Minimal bound of the range
  600. * @param max Maximum bound of the range
  601. * @return True, if val is in the range
  602. */
  603. bool inRange(float val, float min, float max)
  604. {
  605. assert(min >= 0. && min < 10.0);
  606. assert(max >= 0. && max <= 10.0);
  607. assert(val >= 0. && val < 10.0);
  608. if (min <= max)
  609. {
  610. return min <= val && val <= max;
  611. }
  612. else
  613. {
  614. // e.g. between 8 and 2 (of the next round)
  615. return (min <= val && val < 10.) || (0. <= val && val <= max);
  616. }
  617. }
  618. /**
  619. * @brief Synchronizes a potential misalignment between analog and digital part
  620. *
  621. * @param The current value assembled from digits (pre comma) and analogs (post comma)
  622. * @param digitalPrecision The post-comma value of the last digit ([0...9])
  623. * @param analogDigitalShift The value of the 0.1 analog, when the digital precision == 5 in [0, 9.9]
  624. *
  625. * We define 3 phases:
  626. * - Pre transition: analog post comma < analogDigitalShift && not in transition
  627. * - Transition: Digital Precision in range 1...9
  628. * - Post transition: analog post comma > analogDigitalShift && not in transition
  629. *
  630. * @return The synchronized values as a string
  631. */
  632. std::string syncDigitalAnalog(const std::string& value, const std::string& digitalPrecision,
  633. double analogDigitalShift)
  634. {
  635. if (digitalPrecision.empty())
  636. {
  637. return value;
  638. }
  639. const auto pos = value.find('.');
  640. if (pos == std::string::npos)
  641. {
  642. return value;
  643. }
  644. // disassemble value into pre and post comma part
  645. const auto preComma = value.substr(0, pos);
  646. // memorize, to be able to assemble right numbers of leading zeros
  647. const size_t nPreComma = preComma.size();
  648. const auto postComma = value.substr(pos+1);
  649. const float digitalPostComma = std::atof(digitalPrecision.c_str());
  650. int digitalPreComma = std::atoi(preComma.c_str());
  651. const float analogPostComma = std::atof(("0." + postComma).c_str());
  652. // Determine phase
  653. const bool inTransition = digitalPostComma > 0. && digitalPostComma < 10.;
  654. const bool postTransition = !inTransition && inRange(analogPostComma*10., analogDigitalShift, wrapAround(analogDigitalShift + 5.));
  655. const bool preTransition = !inTransition && inRange(analogPostComma*10., 0, analogDigitalShift);
  656. if (inRange(analogDigitalShift, 0.5, 5.))
  657. {
  658. // late transition, last digit starts transition, when analog is between [0.5, 5)
  659. if (inTransition || preTransition)
  660. {
  661. ESP_LOGD("syncDigitalAnalog", "Late digital transition. Increase digital value by 1.");
  662. digitalPreComma += 1;
  663. }
  664. }
  665. else if (inRange(analogDigitalShift, 5., 9.5))
  666. {
  667. // early transition
  668. if (postTransition && analogPostComma*10 > analogDigitalShift)
  669. {
  670. ESP_LOGD("syncDigitalAnalog", "Early digital transition. Decrease digital value by 1.");
  671. digitalPreComma -= 1;
  672. }
  673. // transition has not finished, but we are already at the new cycle
  674. // this also should handle hanging digits
  675. if (inTransition && analogPostComma < 0.5) {
  676. digitalPreComma += 1;
  677. }
  678. }
  679. else
  680. {
  681. return value;
  682. }
  683. // assemble result into string again, pad with zeros
  684. auto preCommaNew = std::to_string(digitalPreComma);
  685. for (size_t i = preCommaNew.size(); i < nPreComma; ++i)
  686. preCommaNew = "0" + preCommaNew;
  687. const std::string result = preCommaNew + "." + postComma;
  688. #if debugSync
  689. ESP_LOGD("syncDigitalAnalog", "result: %s", result.c_str());
  690. #endif
  691. return result;
  692. }
  693. bool ClassFlowPostProcessing::doFlow(string zwtime)
  694. {
  695. string result = "";
  696. string digit = "";
  697. string analog = "";
  698. string zwvalue;
  699. string zw;
  700. time_t imagetime = 0;
  701. string rohwert;
  702. // Update decimal point, as the decimal places can also change when changing from CNNType Auto --> xyz:
  703. imagetime = flowTakeImage->getTimeImageTaken();
  704. if (imagetime == 0)
  705. time(&imagetime);
  706. struct tm* timeinfo;
  707. timeinfo = localtime(&imagetime);
  708. char strftime_buf[64];
  709. strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%dT%H:%M:%S", timeinfo);
  710. zwtime = std::string(strftime_buf);
  711. ESP_LOGD(TAG, "Quantity NUMBERS: %d", NUMBERS.size());
  712. for (int j = 0; j < NUMBERS.size(); ++j)
  713. {
  714. NUMBERS[j]->ReturnRawValue = "";
  715. NUMBERS[j]->ReturnRateValue = "";
  716. NUMBERS[j]->ReturnValue = "";
  717. NUMBERS[j]->ErrorMessageText = "";
  718. NUMBERS[j]->Value = -1;
  719. /* calculate time difference BEFORE we overwrite the 'lastvalue' */
  720. double difference = difftime(imagetime, NUMBERS[j]->lastvalue); // in seconds
  721. /* TODO:
  722. * We could call `NUMBERS[j]->lastvalue = imagetime;` here and remove all other such calls further down.
  723. * But we should check nothing breaks! */
  724. UpdateNachkommaDecimalShift();
  725. int previous_value = -1;
  726. // ------------------- start processing analog values --------------------------//
  727. if (NUMBERS[j]->analog_roi)
  728. {
  729. NUMBERS[j]->ReturnRawValue = flowAnalog->getReadout(j, NUMBERS[j]->isExtendedResolution);
  730. if (NUMBERS[j]->ReturnRawValue.length() > 0)
  731. {
  732. char zw = NUMBERS[j]->ReturnRawValue[0];
  733. if (zw >= 48 && zw <=57)
  734. previous_value = zw - 48;
  735. }
  736. }
  737. #ifdef SERIAL_DEBUG
  738. ESP_LOGD(TAG, "After analog->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
  739. #endif
  740. // ----------------- start processing digital values --------------------------//
  741. // we need the precision of the digital values to determine transition phase
  742. std::string digitalPrecision = {"0"};
  743. if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi) {
  744. // we have nachkommad and vorkomman part!
  745. std::string analogValues = NUMBERS[j]->ReturnRawValue;
  746. std::string digitValues = flowDigit->getReadout(j, true, previous_value, NUMBERS[j]->analog_roi->ROI[0]->result_float, 0.);
  747. if (flowDigit->getCNNType() != Digital)
  748. {
  749. // The digital type does not provide an extended resolution, so we cannot extract it
  750. digitalPrecision = digitValues.substr(digitValues.size() - 1);
  751. digitValues = digitValues.substr(0, digitValues.size() - 1);
  752. }
  753. NUMBERS[j]->ReturnRawValue = digitValues + "." + analogValues;
  754. }
  755. if (NUMBERS[j]->digit_roi && !NUMBERS[j]->analog_roi)
  756. {
  757. NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution, previous_value); // Extended Resolution only if there are no analogue digits
  758. }
  759. #ifdef SERIAL_DEBUG
  760. ESP_LOGD(TAG, "After digital->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
  761. #endif
  762. // ------------------ start corrections --------------------------//
  763. NUMBERS[j]->ReturnRawValue = ShiftDecimal(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->DecimalShift);
  764. #ifdef SERIAL_DEBUG
  765. ESP_LOGD(TAG, "After ShiftDecimal: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
  766. #endif
  767. if (IgnoreLeadingNaN)
  768. while ((NUMBERS[j]->ReturnRawValue.length() > 1) && (NUMBERS[j]->ReturnRawValue[0] == 'N'))
  769. NUMBERS[j]->ReturnRawValue.erase(0, 1);
  770. #ifdef SERIAL_DEBUG
  771. ESP_LOGD(TAG, "After IgnoreLeadingNaN: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
  772. #endif
  773. NUMBERS[j]->ReturnValue = NUMBERS[j]->ReturnRawValue;
  774. if (findDelimiterPos(NUMBERS[j]->ReturnValue, "N") != std::string::npos)
  775. {
  776. if (PreValueUse && NUMBERS[j]->PreValueOkay)
  777. {
  778. NUMBERS[j]->ReturnValue = ErsetzteN(NUMBERS[j]->ReturnValue, NUMBERS[j]->PreValue);
  779. }
  780. else
  781. {
  782. string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
  783. LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw);
  784. /* TODO to be discussed, see https://github.com/jomjol/AI-on-the-edge-device/issues/1617 */
  785. NUMBERS[j]->lastvalue = imagetime;
  786. WriteDataLog(j);
  787. continue; // there is no number because there is still an N.
  788. }
  789. }
  790. if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
  791. {
  792. // Synchronize potential misalignment between analog and digital part
  793. NUMBERS[j]->ReturnValue = syncDigitalAnalog(NUMBERS[j]->ReturnValue, digitalPrecision, NUMBERS[j]->AnalogDigitalTransitionStart);
  794. }
  795. #ifdef SERIAL_DEBUG
  796. ESP_LOGD(TAG, "After findDelimiterPos: ReturnValue %s", NUMBERS[j]->ReturnRawValue.c_str());
  797. #endif
  798. // Delete leading zeros (unless there is only one 0 left)
  799. while ((NUMBERS[j]->ReturnValue.length() > 1) && (NUMBERS[j]->ReturnValue[0] == '0'))
  800. NUMBERS[j]->ReturnValue.erase(0, 1);
  801. #ifdef SERIAL_DEBUG
  802. ESP_LOGD(TAG, "After removeLeadingZeros: ReturnValue %s", NUMBERS[j]->ReturnRawValue.c_str());
  803. #endif
  804. NUMBERS[j]->Value = std::stod(NUMBERS[j]->ReturnValue);
  805. #ifdef SERIAL_DEBUG
  806. ESP_LOGD(TAG, "After setting the Value: Value %f and as double is %f", NUMBERS[j]->Value, std::stod(NUMBERS[j]->ReturnValue));
  807. #endif
  808. if (NUMBERS[j]->checkDigitIncreaseConsistency)
  809. {
  810. if (flowDigit)
  811. {
  812. if (flowDigit->getCNNType() != Digital)
  813. ESP_LOGD(TAG, "checkDigitIncreaseConsistency = true - ignored due to wrong CNN-Type (not Digital Classification)");
  814. else
  815. NUMBERS[j]->Value = checkDigitConsistency(NUMBERS[j]->Value, NUMBERS[j]->DecimalShift, NUMBERS[j]->analog_roi != NULL, NUMBERS[j]->PreValue);
  816. }
  817. else
  818. {
  819. #ifdef SERIAL_DEBUG
  820. ESP_LOGD(TAG, "checkDigitIncreaseConsistency = true - no digital numbers defined!");
  821. #endif
  822. }
  823. }
  824. #ifdef SERIAL_DEBUG
  825. ESP_LOGD(TAG, "After checkDigitIncreaseConsistency: Value %f", NUMBERS[j]->Value);
  826. #endif
  827. if (!NUMBERS[j]->AllowNegativeRates)
  828. {
  829. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handleAllowNegativeRate for device: " + NUMBERS[j]->name);
  830. if ((NUMBERS[j]->Value < NUMBERS[j]->PreValue))
  831. {
  832. // more debug if extended resolution is on, see #2447
  833. if (NUMBERS[j]->isExtendedResolution) {
  834. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Neg: value=" + std::to_string(NUMBERS[j]->Value)
  835. + ", preValue=" + std::to_string(NUMBERS[j]->PreValue)
  836. + ", preToll=" + std::to_string(NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))));
  837. }
  838. // Include inaccuracy of 0.2 for isExtendedResolution.
  839. if ((NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))) && NUMBERS[j]->isExtendedResolution)
  840. // not extended resolution allows -1 on the lowest digit
  841. || (NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(1/pow(10, NUMBERS[j]->Nachkomma))) && !NUMBERS[j]->isExtendedResolution)) {
  842. NUMBERS[j]->Value = NUMBERS[j]->PreValue;
  843. NUMBERS[j]->ReturnValue = to_string(NUMBERS[j]->PreValue);
  844. }
  845. else {
  846. NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Neg. Rate - Read: " + zwvalue + " - Raw: " + NUMBERS[j]->ReturnRawValue + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " ";
  847. NUMBERS[j]->Value = NUMBERS[j]->PreValue;
  848. NUMBERS[j]->ReturnValue = "";
  849. NUMBERS[j]->lastvalue = imagetime;
  850. string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
  851. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, _zw);
  852. WriteDataLog(j);
  853. continue;
  854. }
  855. }
  856. }
  857. #ifdef SERIAL_DEBUG
  858. ESP_LOGD(TAG, "After AllowNegativeRates: Value %f", NUMBERS[j]->Value);
  859. #endif
  860. difference /= 60;
  861. NUMBERS[j]->FlowRateAct = (NUMBERS[j]->Value - NUMBERS[j]->PreValue) / difference;
  862. NUMBERS[j]->ReturnRateValue = to_string(NUMBERS[j]->FlowRateAct);
  863. if (NUMBERS[j]->useMaxRateValue && PreValueUse && NUMBERS[j]->PreValueOkay)
  864. {
  865. double _ratedifference;
  866. if (NUMBERS[j]->RateType == RateChange)
  867. _ratedifference = NUMBERS[j]->FlowRateAct;
  868. else
  869. _ratedifference = (NUMBERS[j]->Value - NUMBERS[j]->PreValue);
  870. if (abs(_ratedifference) > abs(NUMBERS[j]->MaxRateValue))
  871. {
  872. NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Rate too high - Read: " + RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma) + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " - Rate: " + RundeOutput(_ratedifference, NUMBERS[j]->Nachkomma);
  873. NUMBERS[j]->Value = NUMBERS[j]->PreValue;
  874. NUMBERS[j]->ReturnValue = "";
  875. NUMBERS[j]->ReturnRateValue = "";
  876. NUMBERS[j]->lastvalue = imagetime;
  877. string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
  878. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, _zw);
  879. WriteDataLog(j);
  880. continue;
  881. }
  882. }
  883. #ifdef SERIAL_DEBUG
  884. ESP_LOGD(TAG, "After MaxRateCheck: Value %f", NUMBERS[j]->Value);
  885. #endif
  886. NUMBERS[j]->ReturnChangeAbsolute = RundeOutput(NUMBERS[j]->Value - NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
  887. NUMBERS[j]->PreValue = NUMBERS[j]->Value;
  888. NUMBERS[j]->PreValueOkay = true;
  889. NUMBERS[j]->lastvalue = imagetime;
  890. NUMBERS[j]->ReturnValue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma);
  891. NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
  892. NUMBERS[j]->ErrorMessageText = "no error";
  893. UpdatePreValueINI = true;
  894. string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
  895. LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw);
  896. WriteDataLog(j);
  897. }
  898. SavePreValue();
  899. return true;
  900. }
  901. void ClassFlowPostProcessing::WriteDataLog(int _index)
  902. {
  903. if (!LogFile.GetDataLogToSD()){
  904. return;
  905. }
  906. string analog = "";
  907. string digital = "";
  908. string timezw = "";
  909. char buffer[80];
  910. struct tm* timeinfo = localtime(&NUMBERS[_index]->lastvalue);
  911. strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
  912. timezw = std::string(buffer);
  913. if (flowAnalog)
  914. analog = flowAnalog->getReadoutRawString(_index);
  915. if (flowDigit)
  916. digital = flowDigit->getReadoutRawString(_index);
  917. LogFile.WriteToData(timezw, NUMBERS[_index]->name,
  918. NUMBERS[_index]->ReturnRawValue, NUMBERS[_index]->ReturnValue, NUMBERS[_index]->ReturnPreValue,
  919. NUMBERS[_index]->ReturnRateValue, NUMBERS[_index]->ReturnChangeAbsolute,
  920. NUMBERS[_index]->ErrorMessageText,
  921. digital, analog);
  922. ESP_LOGD(TAG, "WriteDataLog: %s, %s, %s, %s, %s", NUMBERS[_index]->ReturnRawValue.c_str(), NUMBERS[_index]->ReturnValue.c_str(), NUMBERS[_index]->ErrorMessageText.c_str(), digital.c_str(), analog.c_str());
  923. }
  924. void ClassFlowPostProcessing::UpdateNachkommaDecimalShift()
  925. {
  926. for (int j = 0; j < NUMBERS.size(); ++j)
  927. {
  928. if (NUMBERS[j]->digit_roi && !NUMBERS[j]->analog_roi) // There are only digital digits
  929. {
  930. // ESP_LOGD(TAG, "Nurdigital");
  931. NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
  932. if (NUMBERS[j]->isExtendedResolution && flowDigit->isExtendedResolution()) // Extended resolution is on and should also be used for this digit.
  933. NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShift-1;
  934. NUMBERS[j]->Nachkomma = -NUMBERS[j]->DecimalShift;
  935. }
  936. if (!NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
  937. {
  938. // ESP_LOGD(TAG, "Nur analog");
  939. NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
  940. if (NUMBERS[j]->isExtendedResolution && flowAnalog->isExtendedResolution())
  941. NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShift-1;
  942. NUMBERS[j]->Nachkomma = -NUMBERS[j]->DecimalShift;
  943. }
  944. if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi) // digital + analog
  945. {
  946. // ESP_LOGD(TAG, "Nur digital + analog");
  947. NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
  948. NUMBERS[j]->Nachkomma = NUMBERS[j]->analog_roi->ROI.size() - NUMBERS[j]->DecimalShift;
  949. if (NUMBERS[j]->isExtendedResolution && flowAnalog->isExtendedResolution()) // Extended resolution is on and should also be used for this digit.
  950. NUMBERS[j]->Nachkomma = NUMBERS[j]->Nachkomma+1;
  951. }
  952. ESP_LOGD(TAG, "UpdateNachkommaDecShift NUMBER%i: Nachkomma %i, DecShift %i", j, NUMBERS[j]->Nachkomma,NUMBERS[j]->DecimalShift);
  953. }
  954. }
  955. string ClassFlowPostProcessing::getReadout(int _number)
  956. {
  957. return NUMBERS[_number]->ReturnValue;
  958. }
  959. string ClassFlowPostProcessing::getReadoutParam(bool _rawValue, bool _noerror, int _number)
  960. {
  961. if (_rawValue)
  962. return NUMBERS[_number]->ReturnRawValue;
  963. if (_noerror)
  964. return NUMBERS[_number]->ReturnValue;
  965. return NUMBERS[_number]->ReturnValue;
  966. }
  967. string ClassFlowPostProcessing::ErsetzteN(string input, double _prevalue)
  968. {
  969. int posN, posPunkt;
  970. int pot, ziffer;
  971. float zw;
  972. posN = findDelimiterPos(input, "N");
  973. posPunkt = findDelimiterPos(input, ".");
  974. if (posPunkt == std::string::npos){
  975. posPunkt = input.length();
  976. }
  977. while (posN != std::string::npos)
  978. {
  979. if (posN < posPunkt) {
  980. pot = posPunkt - posN - 1;
  981. }
  982. else {
  983. pot = posPunkt - posN;
  984. }
  985. zw =_prevalue / pow(10, pot);
  986. ziffer = ((int) zw) % 10;
  987. input[posN] = ziffer + 48;
  988. posN = findDelimiterPos(input, "N");
  989. }
  990. return input;
  991. }
  992. float ClassFlowPostProcessing::checkDigitConsistency(double input, int _decilamshift, bool _isanalog, double _preValue){
  993. int aktdigit, olddigit;
  994. int aktdigit_before, olddigit_before;
  995. int pot, pot_max;
  996. float zw;
  997. bool no_nulldurchgang = false;
  998. pot = _decilamshift;
  999. if (!_isanalog) // if there are no analogue values, the last one cannot be evaluated
  1000. {
  1001. pot++;
  1002. }
  1003. #ifdef SERIAL_DEBUG
  1004. ESP_LOGD(TAG, "checkDigitConsistency: pot=%d, decimalshift=%d", pot, _decilamshift);
  1005. #endif
  1006. pot_max = ((int) log10(input)) + 1;
  1007. while (pot <= pot_max)
  1008. {
  1009. zw = input / pow(10, pot-1);
  1010. aktdigit_before = ((int) zw) % 10;
  1011. zw = _preValue / pow(10, pot-1);
  1012. olddigit_before = ((int) zw) % 10;
  1013. zw = input / pow(10, pot);
  1014. aktdigit = ((int) zw) % 10;
  1015. zw = _preValue / pow(10, pot);
  1016. olddigit = ((int) zw) % 10;
  1017. no_nulldurchgang = (olddigit_before <= aktdigit_before);
  1018. if (no_nulldurchgang)
  1019. {
  1020. if (aktdigit != olddigit)
  1021. {
  1022. input = input + ((float) (olddigit - aktdigit)) * pow(10, pot); // New Digit is replaced by old Digit;
  1023. }
  1024. }
  1025. else
  1026. {
  1027. if (aktdigit == olddigit) // despite zero crossing, digit was not incremented --> add 1
  1028. {
  1029. input = input + ((float) (1)) * pow(10, pot); // add 1 at the point
  1030. }
  1031. }
  1032. #ifdef SERIAL_DEBUG
  1033. ESP_LOGD(TAG, "checkDigitConsistency: input=%f", input);
  1034. #endif
  1035. pot++;
  1036. }
  1037. return input;
  1038. }
  1039. string ClassFlowPostProcessing::getReadoutRate(int _number)
  1040. {
  1041. return std::to_string(NUMBERS[_number]->FlowRateAct);
  1042. }
  1043. string ClassFlowPostProcessing::getReadoutTimeStamp(int _number)
  1044. {
  1045. return NUMBERS[_number]->timeStamp;
  1046. }
  1047. string ClassFlowPostProcessing::getReadoutError(int _number)
  1048. {
  1049. return NUMBERS[_number]->ErrorMessageText;
  1050. }