From 1c6ffdf61dbf524ea49f9903425f7db21ec1006f Mon Sep 17 00:00:00 2001 From: Eilert Tunheim <emtunhei@stud.ntnu.no> Date: Mon, 2 May 2022 09:02:50 +0200 Subject: [PATCH] Added function to search for live data during drying process --- .../java/com/application/DB/Constants.java | 11 ++-- src/main/java/com/application/DB/DB.java | 61 +++++++++++------- .../com/application/DB/HelpingFunctions.java | 32 +++++++++ .../com/application/GUI/InputPopUpWindow.java | 25 +++++++ .../com/application/DB/Constants.class | Bin 6168 -> 6466 bytes .../application/GUI/InputPopUpWindow.class | Bin 7181 -> 7425 bytes 6 files changed, 100 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/application/DB/Constants.java b/src/main/java/com/application/DB/Constants.java index ce33886..2ea1fe0 100644 --- a/src/main/java/com/application/DB/Constants.java +++ b/src/main/java/com/application/DB/Constants.java @@ -18,10 +18,9 @@ public final class Constants { // Today's date public static final String TODAYS_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()); - // Start- & end time public static String START_TIME = ""; - public static String STOP_TIME = ""; + public static String STOP_TIME = TODAYS_DATE; // User inputs public static String TREE_SPECIES = ""; @@ -35,11 +34,15 @@ public final class Constants { // Non linear regression public static final double ADJUST_REGRESSION = 5.5; - // Database ID/name + // Current sawmill settings; public static final String PROJECT_ID = "sf-drying-optimization"; - public static final int LOCATION_ID = 124; public static final String MAN_MOISTURE_TABLE = "int_dk_manMoisture"; + public static final String KWH_TABLE_NAME = "int_sd_winccsensordata"; + public static final String KWH_NAME_PARAMETER = "VariantValue"; + public static final String KWH_TIMESTAMP_NAME_PARAMETER = "Timestamp"; + public static final String KWH_VALUE_ID_NAME_PARAMETER = "ValueID"; + public static final String KWH_VALUE_ID_VALUE_PARAMETER = "51"; // Which chamber is used // Location Valasen(124) diff --git a/src/main/java/com/application/DB/DB.java b/src/main/java/com/application/DB/DB.java index 17cfb2c..cb88cf9 100644 --- a/src/main/java/com/application/DB/DB.java +++ b/src/main/java/com/application/DB/DB.java @@ -267,31 +267,7 @@ public class DB { //System.out.println("Timestamp \t kWh"); int baseline = 0; - for (FieldValueList row : result.iterateAll()) { - - // Sets the baseline in order to reset the kWh counter - if (baseline == 0) { - baseline = row.get("" + KwhName + "").getNumericValue().intValue(); - } - //System.out.println("baseline: "+baseline); - - // kWh value - int variantValue = row.get("" + KwhName + "").getNumericValue().intValue() - baseline; //-baseline - - // Retrieving the wanted data - long timeStamp = row.get("" + timestamp + "").getTimestampValue() / 1000; - // Riktig format, men i string - String formatedTimeStamp = HelpingFunctions.getDateFormat().format(timeStamp); - - // Checks for negative values - if (variantValue > 0) { - // Adding the data to a list in order to sort through later - data.put(formatedTimeStamp, variantValue); - } - - //System.out.printf("Timestamp: \t%s\t\t\tkWh: \t%s\t\t\tBaseline: %s\n",formatedTimeStamp,variantValue,baseline); - // Checks if the data is empty - } + HelpingFunctions.iterateKwhValues(data, baseline, result, KwhName, timestamp); System.out.println("Data size: " + data.size()); @@ -597,4 +573,39 @@ public class DB { HelpingFunctions.createQueryJob(sqlStatement); } + + /** + * Retrieves data from current drying process + * + * @return a map consisting of Timestamp(date&time) and Kwh value + * @throws Exception throws execution if anything is wrong + */ + public static Map<String, Number> getCurrentDrying() throws Exception { + + // Initializing the data map to store the results + Map<String, Number> data = new HashMap<>(); + // Initializing baseline + int baseline = 0; + + // Sqlstatement + final String sqlStatement = "SELECT `" + KWH_TIMESTAMP_NAME_PARAMETER + "`, `" + KWH_NAME_PARAMETER + "` " + + "FROM `" + PROJECT_ID + "." + LOCATION_ID + "." + KWH_TABLE_NAME + "` " + + "WHERE " + KWH_TIMESTAMP_NAME_PARAMETER + " BETWEEN " + '"' + START_TIME + '"' + + " AND " + '"' + STOP_TIME + '"' + + " AND " + KWH_VALUE_ID_NAME_PARAMETER + " = " + KWH_VALUE_ID_VALUE_PARAMETER + " " + + " AND " + KWH_NAME_PARAMETER + " <> 0 " + + " ORDER BY " + KWH_TIMESTAMP_NAME_PARAMETER + " ASC"; + + System.out.println(sqlStatement); + + // Retrieves the results from the queryjob + TableResult result = HelpingFunctions.createQueryJob(sqlStatement); + + //System.out.println("InTidTork\t\t\tUtTidTork"); + // Iterating through the results + HelpingFunctions.iterateKwhValues(data, baseline, result, KWH_NAME_PARAMETER, KWH_TIMESTAMP_NAME_PARAMETER); + return new TreeMap<>(data); + } + + } diff --git a/src/main/java/com/application/DB/HelpingFunctions.java b/src/main/java/com/application/DB/HelpingFunctions.java index 5467ca7..a34f4f5 100644 --- a/src/main/java/com/application/DB/HelpingFunctions.java +++ b/src/main/java/com/application/DB/HelpingFunctions.java @@ -117,4 +117,36 @@ public class HelpingFunctions { public static Map<String, String> getManMoist() { return manMoist; } + + /** + * Function to iterate through all the Kwh values and storing them in a map + * + * @param data a map to store all the data + * @param baseline a baseline to base all the next values of to get a zero point + * @param result TableResult to iterate through + * @param kwhNameParameter Name of the Kwh name parameter in the database + * @param kwhTimestampNameParameter Name of the timestamp parameter in the database + */ + static void iterateKwhValues(Map<String, Number> data, int baseline, TableResult result, String kwhNameParameter, String kwhTimestampNameParameter) { + for (FieldValueList row : result.iterateAll()) { + // Sets the baseline in order to reset the kWh counter + if (baseline == 0) { + baseline = row.get("" + kwhNameParameter + "").getNumericValue().intValue(); + } + + // kWh value + int variantValue = row.get("" + kwhNameParameter + "").getNumericValue().intValue() - baseline; //-baseline + + // Retrieving the wanted data + long timeStamp = row.get("" + kwhTimestampNameParameter + "").getTimestampValue() / 1000; + // Riktig format, men i string + String formatedTimeStamp = getDateFormat().format(timeStamp); + + // Checks for negative values + if (variantValue > 0) { + // Adding the data to a list in order to sort through later + data.put(formatedTimeStamp, variantValue); + } + } + } } diff --git a/src/main/java/com/application/GUI/InputPopUpWindow.java b/src/main/java/com/application/GUI/InputPopUpWindow.java index 1d26d63..a4071ed 100644 --- a/src/main/java/com/application/GUI/InputPopUpWindow.java +++ b/src/main/java/com/application/GUI/InputPopUpWindow.java @@ -13,6 +13,7 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import static com.application.DB.Constants.*; +import static com.application.DB.DB.getCurrentDrying; import static com.application.Main.*; import static com.application.DB.DB.setInputParameters; import static com.application.GUI.LineChartFunctionality.loadSingleSeries; @@ -247,7 +248,31 @@ public class InputPopUpWindow { ex.printStackTrace(); } + // Retrieve data for current drying period + try{ + Thread thread = new Thread(() -> { + try { + + // Henter her data fra databasen + Map<String, Number> data = getCurrentDrying(); + Platform.runLater(() -> { + try { + //loadSingleSeries(data); + } catch (Exception ex) { + ex.printStackTrace(); + } + }); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + ); + thread.setDaemon(true); + thread.start(); + } catch (Exception ex) { + ex.printStackTrace(); + } } diff --git a/target/classes/com/application/DB/Constants.class b/target/classes/com/application/DB/Constants.class index 63ce6b6ba5f67a9529377d76c676478db897eb76..86a1941d22a795754d864cc38476bcc881177aec 100644 GIT binary patch delta 2649 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 KSO6~d76Jh3sGvOn delta 2387 zcmX?PG{d0&)W2Q(7#J8#7+!HPSTM|BXPC*wzyzXaaWR-O%;sWXVVDCFnG0gg0}=B% z7#4s;7J@j7I2aa#=p`HsOF0;paWE|BU|7Myu#$se6$is=4u&;c3~L$IaWb$ltmk0Z zz`?MQgJBZ~!)6YKEg-S2T=fhr4BJ2kYzGlLI2d+vFzn)B*v-MP2c%#x2g5!Py`O{O z02jkShC^HohZ&B5SVuv^$2b^{gXj|=;v|ST1tLy^h%@XAXW1FfaWR}{xWL6=!f=tD z;SwVQcZk1>V`Ol=i(`l@BZH97WDZ8*$tH~5jF%@LVANu~vblii1ry`d&5^8gS()=0 z3MT*LGPS<OaGi&tmZ6-7;ReG^9)=zetC69ck%2QTF()^*Br~~~hv62(Z61aekSMcv zc?J(dCy1#q*^ftdavOIh_Z=RFYYcaJ7(yAsCja8L7m8sB<6-CnnbZ#=CNY#x_U4I7 zNMi_NWZ(=+P0R^P%qdOfVaNgr2v=5CR_glt>ZYV9cz9Ul=2{gOvoqY|VYtumfSutX z55psd$2<&A7@qPlSTa~KGBEHkSTk7hFxY?yTM%IfBJ3F)CiC;^a6jW=c+T*GhasQg z<zzQr=gob*Dophj3=9lv43Z!N7#J8hK?Z<n8wM*dZ40ICptL=M0|NttB!eS^69XfI zGXnzy6N3wbB!e4+6`b$RAj#mt-~i`)GDtFbA<26)NHX|9<m<r(fE4&5Dd1<2Wbi}c z3ouAB_#^QJ86+73koZCjk_>@Jd=Umoh9D%qD1#(JFvLQzeIX2zpcr9bWT+1Z3q&wT zGDIS2kYbQzh(h8^Ge|N-Bk^S!BpG5D!WbAC5c*@0EQn)}WQa#nuf!n9kbuNjW{_k^ z1o7*kK?w3u5=a2b2l*%&iLb&S$&iA?S7nf7NJX*`<fAk+2c;vaS7(r9$Ux$QJe0{` z#ZV86Ly(WM&<w~%(vZU-$&ia=VIBiN0~13&LjeOLLm>kLgE0dm10w?i1FP0{2F8ux zKrLcmU;vdE3=Dh>EDQn+#SEYn3Rc8W!cYoMUhHKI<qS*=g_EZUnfZb=2r;lQFfgPs za4@7Zh%#g_C^KZjHF7Y>GE^{BGB7YyL5+flR5LI@<DrIu3zTEQCW;GNBbk`bz`;<! zAi+?`putdtWTFy79h!+C5m2&(#B2itCqpCDjfP?pleY_tBAHsoz`;<?AjnX`AjMFL zWU2^;sUVRixI3E}xIl#l*qy7zv?e=?DAj{}FUP>nz`#(;z`;<*AjnY9AjQzYpv=(7 zpu^D2V9C&eWP>q7E1J7OBFHvyGPE(YgKS`6V2}aF4FdzqCI*QO3=9m63?SRsz@i<H zu;XFqVBi83Umz`$KZuxt9VEuU%D}+T!@$AN%OJ?m#~{Vf&!EgO3CSU{3|(jr0g0eG zq#K(<<j@^54dM{6J9-$(S-=iiDT*A6a~L=n<}yey%wy1Cn2+QLC5B!!M}S07W3dk& zi@HcLxR`;1VF`mE!%_w*hGj@5g5nD`rGZ3{y~V}Q4>fVMm`@}qJRz~Sih+Y+HG?3- z8U`tbwG7G(>lkzxHZWK+Y(z5Mm|+5%dqE<|rgJh(gaq2;0C7=Skm-=v+KLoNlc4s0 z5RsTXOI!{q!gexnFzjLwWZ2Ch#juA#nPDH2-Ledm(d-6^pxQkJVmE5a(Lj%|LvXin zFid4AsD~B>&luPkKwy=S<_-p}9Sqvr7<4u>=nCm=X3z%_1|Y%^L>RGbW-#8(U=qo? zm%%iWnPUe7Yj7ls02_$j!C<zX!F)4=1VUcG7$gzNB47ccVG8763MwO+1q4Adkt_m2 zAR4AZ4W=TJSwI*h5y=9fVG1-r1r{VvXfbdxFfa%+@G*!n2s4N?NH9n+fXYTC1{nr5 a26F~C2788dhERqMh8PA$hH2n}ZaM&CKw%dE diff --git a/target/classes/com/application/GUI/InputPopUpWindow.class b/target/classes/com/application/GUI/InputPopUpWindow.class index 6f8be194dd66499c7a4cda284470d56527148834..04830397692eb383cf896d85766005d3041e3420 100644 GIT binary patch delta 3194 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 H9HRgLpKXY` delta 2948 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 -- GitLab