├── .gitignore ├── src ├── main │ ├── resources │ │ ├── Dawn.JPG │ │ ├── Thumbs.db │ │ ├── Nightscout.jpg │ │ ├── images │ │ │ ├── Thumbs.db │ │ │ ├── MainPage.jpg │ │ │ ├── FindModify.JPG │ │ │ ├── TrendAnalysis.jpg │ │ │ ├── AnalysisCGMDates.JPG │ │ │ ├── Autotune_MainPage.JPG │ │ │ ├── CGMTrendAnalysis.jpg │ │ │ ├── Autotune_ListBackups.JPG │ │ │ ├── AutotuneManagementRun.JPG │ │ │ ├── TreatmentTrendAnalysis.jpg │ │ │ ├── Autotune_ProfileEditorPage.JPG │ │ │ ├── AutotuneManagementListBackups.JPG │ │ │ └── AutotuneManagementProfileEditor.JPG │ │ └── NightscoutLoader.pdf │ └── java │ │ ├── entity │ │ ├── TextLineReceiverInterface.java │ │ ├── DBResultInterface.java │ │ ├── DBResultPumpSettingCarbRatio.java │ │ ├── DBResultOmniPod.java │ │ ├── DBResultPumpSettingISF.java │ │ ├── ResultFromDBComparator.java │ │ ├── DBResultPumpSettingTarget.java │ │ ├── DBResultPumpSetting.java │ │ ├── DBResultPumpSettingBasal.java │ │ ├── DBResultRoche.java │ │ ├── DBResultEntryLibreView.java │ │ ├── DBResultEntryDiasend.java │ │ ├── DBResultCore.java │ │ ├── DBResultCellNovoRaw.java │ │ ├── DBResultMedtronicOld.java │ │ └── DBResultMedtronicNew.java │ │ ├── win │ │ ├── WinSetDatesInterface.java │ │ ├── WinAbout.java │ │ ├── WinTextWin.java │ │ └── WinWhy.java │ │ ├── control │ │ ├── MainControlInterface.java │ │ ├── ThreadAutotuneRun.java │ │ ├── ThreadAutotuneListBackups.java │ │ ├── ThreadMongoDBAlerterEntries.java │ │ ├── ThreadMongoDBAlerterTreatments.java │ │ ├── ThreadAutotuneRemoteSaveAs.java │ │ ├── ThreadAutotuneDownloadBackups.java │ │ ├── MainNightScoutLoader.java │ │ ├── ThreadHelpLauncher.java │ │ ├── ThreadAutotune.java │ │ ├── ThreadDataLoad.java │ │ ├── ThreadAnalyzer.java │ │ └── ThreadMongoDBAlerter.java │ │ ├── loader │ │ ├── DataLoadFile.java │ │ ├── AuditLogComparator.java │ │ ├── DataLoadNightScoutEntries.java │ │ ├── DataLoadRocheCSV.java │ │ ├── DataLoadLibreView.java │ │ ├── DataLoadCellNovo.java │ │ └── DataLoadMedtronic.java │ │ ├── miscellaneous │ │ ├── OmniPodBinaryFileRecord.java │ │ ├── OmniPodBinaryLogFileSection.java │ │ ├── BinaryFileFieldValue.java │ │ ├── OmniPodBinaryFileSectionComparator.java │ │ ├── DateLabelFormatter.java │ │ ├── OmniPodValidator.java │ │ ├── BinaryFileFieldAccess.java │ │ ├── OmniPodBinaryFileSection.java │ │ ├── FileChecker.java │ │ └── BinaryStruct.java │ │ ├── analysis │ │ ├── AnalyzerID.java │ │ ├── AnalyzerEntriesCGMDay.java │ │ ├── AnalyzerTrendResultEntryComparator.java │ │ ├── AnalyzerTrendResultEntryAggregate.java │ │ ├── AnalyzerTabs.java │ │ └── AnalyzerTrendResultEntry.java │ │ ├── utils │ │ └── DatePatternFormat.java │ │ └── mongo │ │ └── NightscoutMongoDB.java └── test │ ├── resources │ ├── Sample_Diasend.xls │ ├── Sample_Diasend2.xls │ ├── Sample_Diasend_forCoding.xls │ └── Sample_Libreview_forCoding.xlsx │ └── java │ ├── loader │ ├── TestDiasendTreatmentInsCarbNotMerged.java │ ├── BaseTestEntry.java │ └── BaseTestTreatment.java │ └── control │ └── TestMongoConnection.java ├── .project ├── bin ├── loadDiasend.sh ├── loadLibreview.sh └── NightScoutLoader.bat ├── .classpath └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .settings 2 | target 3 | .classpath 4 | .project 5 | .idea -------------------------------------------------------------------------------- /src/main/resources/Dawn.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/Dawn.JPG -------------------------------------------------------------------------------- /src/main/resources/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/Thumbs.db -------------------------------------------------------------------------------- /src/main/resources/Nightscout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/Nightscout.jpg -------------------------------------------------------------------------------- /src/main/resources/images/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/Thumbs.db -------------------------------------------------------------------------------- /src/main/resources/images/MainPage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/MainPage.jpg -------------------------------------------------------------------------------- /src/test/resources/Sample_Diasend.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/test/resources/Sample_Diasend.xls -------------------------------------------------------------------------------- /src/test/resources/Sample_Diasend2.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/test/resources/Sample_Diasend2.xls -------------------------------------------------------------------------------- /src/main/resources/NightscoutLoader.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/NightscoutLoader.pdf -------------------------------------------------------------------------------- /src/main/resources/images/FindModify.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/FindModify.JPG -------------------------------------------------------------------------------- /src/main/resources/images/TrendAnalysis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/TrendAnalysis.jpg -------------------------------------------------------------------------------- /src/main/resources/images/AnalysisCGMDates.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/AnalysisCGMDates.JPG -------------------------------------------------------------------------------- /src/main/resources/images/Autotune_MainPage.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/Autotune_MainPage.JPG -------------------------------------------------------------------------------- /src/main/resources/images/CGMTrendAnalysis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/CGMTrendAnalysis.jpg -------------------------------------------------------------------------------- /src/test/resources/Sample_Diasend_forCoding.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/test/resources/Sample_Diasend_forCoding.xls -------------------------------------------------------------------------------- /src/main/resources/images/Autotune_ListBackups.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/Autotune_ListBackups.JPG -------------------------------------------------------------------------------- /src/test/resources/Sample_Libreview_forCoding.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/test/resources/Sample_Libreview_forCoding.xlsx -------------------------------------------------------------------------------- /src/main/resources/images/AutotuneManagementRun.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/AutotuneManagementRun.JPG -------------------------------------------------------------------------------- /src/main/resources/images/TreatmentTrendAnalysis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/TreatmentTrendAnalysis.jpg -------------------------------------------------------------------------------- /src/main/java/entity/TextLineReceiverInterface.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | public interface TextLineReceiverInterface 4 | { 5 | public void addTextLine(String line); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/images/Autotune_ProfileEditorPage.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/Autotune_ProfileEditorPage.JPG -------------------------------------------------------------------------------- /src/main/resources/images/AutotuneManagementListBackups.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/AutotuneManagementListBackups.JPG -------------------------------------------------------------------------------- /src/main/resources/images/AutotuneManagementProfileEditor.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gh-davidr/NightscoutLoader/HEAD/src/main/resources/images/AutotuneManagementProfileEditor.JPG -------------------------------------------------------------------------------- /src/main/java/win/WinSetDatesInterface.java: -------------------------------------------------------------------------------- 1 | package win; 2 | 3 | import java.util.Date; 4 | 5 | public interface WinSetDatesInterface 6 | { 7 | void setDates(Date startDate, Date endDate); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/control/MainControlInterface.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | public interface MainControlInterface 4 | { 5 | // Simple interface that allows the command line mechanism to exit cleanly 6 | // once all threads are complete 7 | public void shutdown(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/loader/DataLoadFile.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | 3 | import java.io.IOException; 4 | import java.sql.SQLException; 5 | 6 | public abstract class DataLoadFile extends DataLoadBase 7 | { 8 | public abstract void loadDBResults(String fileName) throws IOException, SQLException, ClassNotFoundException; 9 | 10 | public abstract void initialize(String filename); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/miscellaneous/OmniPodBinaryFileRecord.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | 3 | public class OmniPodBinaryFileRecord extends OmniPodBinaryFileSection 4 | { 5 | 6 | OmniPodBinaryFileRecord(String sectionHeader, String encoding, String[] fieldNames) { 7 | super(sectionHeader, encoding, fieldNames); 8 | // TODO Auto-generated constructor stub 9 | } 10 | // OmniPodBinaryFileRecord 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultInterface.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import com.mongodb.BasicDBObject; 4 | 5 | public interface DBResultInterface 6 | { 7 | public long getM_EpochMillies(); 8 | 9 | // Derived classes will implement the concept of proximity duplicates 10 | void setImpactOfProximity(); 11 | 12 | void determineWhetherInProximity(); 13 | 14 | BasicDBObject createNightScoutObject(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/analysis/AnalyzerID.java: -------------------------------------------------------------------------------- 1 | package analysis; 2 | 3 | public class AnalyzerID 4 | { 5 | private int m_ID = 0; // Assign an ID to each result created. 6 | 7 | AnalyzerID(Integer static_ID) 8 | { 9 | synchronized(static_ID) 10 | { 11 | static_ID++; 12 | m_ID = static_ID; 13 | } 14 | } 15 | 16 | /** 17 | * @return the m_ID 18 | */ 19 | public synchronized int getM_ID() { 20 | return m_ID; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/control/ThreadAutotuneRun.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import miscellaneous.RemoteLinuxServer; 4 | 5 | public class ThreadAutotuneRun extends ThreadAutotune 6 | { 7 | 8 | public ThreadAutotuneRun(RemoteLinuxServer autoTuner) 9 | { 10 | super(autoTuner); 11 | } 12 | 13 | @Override 14 | protected void doAutotuneTask() 15 | { 16 | // TODO Auto-generated method stub 17 | m_Autotuner.runAutotune(); 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/main/java/control/ThreadAutotuneListBackups.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import miscellaneous.RemoteLinuxServer; 4 | 5 | public class ThreadAutotuneListBackups extends ThreadAutotune 6 | { 7 | public ThreadAutotuneListBackups(RemoteLinuxServer autoTuner) 8 | { 9 | super(autoTuner); 10 | } 11 | 12 | @Override 13 | protected void doAutotuneTask() 14 | { 15 | // TODO Auto-generated method stub 16 | m_Autotuner.listBackupDirectory(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | NightscoutLoaderMaven 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultPumpSettingCarbRatio.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import org.apache.poi.hssf.usermodel.HSSFRow; 4 | 5 | public class DBResultPumpSettingCarbRatio extends DBResultPumpSetting 6 | { 7 | public DBResultPumpSettingCarbRatio(HSSFRow row) 8 | { 9 | super(row); 10 | } 11 | 12 | /** 13 | * @return the m_CarbRatioValue 14 | */ 15 | public synchronized Double getM_CarbRatioValue() { 16 | return getM_TimeBoundValue(); 17 | } 18 | 19 | /** 20 | * @param m_CarbRatioValue the m_CarbRatioValue to set 21 | */ 22 | public synchronized void setM_CarbRatioValue(Double m_CarbRatioValue) { 23 | setM_TimeBoundValue(m_CarbRatioValue); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/control/ThreadMongoDBAlerterEntries.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.io.IOException; 4 | import java.text.ParseException; 5 | 6 | import utils.CommonUtils; 7 | 8 | public class ThreadMongoDBAlerterEntries extends ThreadMongoDBAlerter 9 | { 10 | private static String m_What = new String("Entries"); 11 | 12 | @Override 13 | protected void checkDBForUpdates() throws IOException, ParseException 14 | { 15 | String result = this.m_DataLoader.getLatestEntriesTime(); 16 | 17 | if (result != null) 18 | { 19 | m_CurrentResultAt = CommonUtils.convertDateString(result); 20 | } 21 | } 22 | 23 | @Override 24 | protected String whatIsChecked() 25 | { 26 | return m_What; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/miscellaneous/OmniPodBinaryLogFileSection.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | 3 | public class OmniPodBinaryLogFileSection 4 | { 5 | private int m_FileOffset; 6 | private OmniPodBinaryFileSection m_OmniPodBinaryFileSection; 7 | 8 | public OmniPodBinaryLogFileSection(int offset, 9 | OmniPodBinaryFileSection fileSection) 10 | { 11 | m_FileOffset = offset; 12 | m_OmniPodBinaryFileSection = fileSection; 13 | } 14 | 15 | /** 16 | * @return the m_FileOffset 17 | */ 18 | public synchronized int getM_FileOffset() { 19 | return m_FileOffset; 20 | } 21 | 22 | /** 23 | * @return the m_OmniPodBinaryFileSection 24 | */ 25 | public synchronized OmniPodBinaryFileSection getM_OmniPodBinaryLogFileSection() { 26 | return m_OmniPodBinaryFileSection; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultOmniPod.java: -------------------------------------------------------------------------------- 1 | //package entity; 2 | // 3 | //import java.util.ArrayList; 4 | // 5 | //import org.DavidRichardson.NightscoutLoaderMaven.OmniPodBinaryFileSection; 6 | // 7 | //public class DBResultOmniPod extends DBResult 8 | //{ 9 | // // For now, keep each record with its own reference to 10 | // // how file should be read. 11 | // private ArrayList m_OmniPodBinaryFileSections = null; 12 | // private byte[] m_OmniPodBytes = null; 13 | // 14 | // DBResultOmniPod(ArrayList fileSections, 15 | // byte[] fileContents, int offset) 16 | // { 17 | // m_OmniPodBinaryFileSections = fileSections; 18 | // m_OmniPodBytes = fileContents; 19 | // } 20 | // 21 | // private void unpack() 22 | // { 23 | // 24 | // } 25 | //} 26 | -------------------------------------------------------------------------------- /src/main/java/utils/DatePatternFormat.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | public class DatePatternFormat 6 | { 7 | private String m_PatternString = null; 8 | private String m_FormatString = null; 9 | private Pattern m_Pattern = null; 10 | 11 | public DatePatternFormat(String m_PatternString, String m_FormatString) { 12 | super(); 13 | this.m_PatternString = m_PatternString; 14 | this.m_FormatString = m_FormatString; 15 | 16 | m_Pattern = Pattern.compile(m_PatternString); 17 | } 18 | 19 | /** 20 | * @return the m_PatternString 21 | */ 22 | public synchronized String getM_PatternString() { 23 | return m_PatternString; 24 | } 25 | 26 | /** 27 | * @return the m_FormatString 28 | */ 29 | public synchronized String getM_FormatString() { 30 | return m_FormatString; 31 | } 32 | 33 | /** 34 | * @return the m_Pattern 35 | */ 36 | public synchronized Pattern getM_Pattern() { 37 | return m_Pattern; 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/control/ThreadMongoDBAlerterTreatments.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.io.IOException; 4 | import java.text.ParseException; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | import utils.CommonUtils; 9 | 10 | public class ThreadMongoDBAlerterTreatments extends ThreadMongoDBAlerter 11 | { 12 | private static String m_What = new String("Treatments"); 13 | 14 | @Override 15 | protected void checkDBForUpdates() throws IOException, ParseException 16 | { 17 | String result = this.m_DataLoader.getLatestTreatmentsTimeAndWho(); 18 | if (result != null) 19 | { 20 | String pattern = "(.*)( by )(.*)"; 21 | Pattern r = Pattern.compile(pattern); 22 | Matcher m = r.matcher(result); 23 | if (m.find()) 24 | { 25 | m_CurrentResultAt = CommonUtils.convertDateString(m.group(1)); 26 | m_CurrentResultBy = m.group(3); 27 | } 28 | } 29 | } 30 | 31 | @Override 32 | protected String whatIsChecked() 33 | { 34 | return m_What; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultPumpSettingISF.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import org.apache.poi.hssf.usermodel.HSSFRow; 4 | 5 | public class DBResultPumpSettingISF extends DBResultPumpSetting 6 | { 7 | private String m_BGUnits; 8 | 9 | public DBResultPumpSettingISF(HSSFRow row, String bgUnits) 10 | { 11 | super(row); 12 | 13 | m_BGUnits = new String(bgUnits); 14 | } 15 | 16 | /** 17 | * @return the m_ISFValue 18 | */ 19 | public synchronized Double getM_ISFValue() { 20 | return getM_TimeBoundValue(); 21 | } 22 | 23 | /** 24 | * @param m_ISFValue the m_ISFValue to set 25 | */ 26 | public synchronized void setM_ISFValue(Double m_ISFValue) { 27 | setM_TimeBoundValue(m_ISFValue); 28 | } 29 | 30 | /** 31 | * @return the m_BGUnits 32 | */ 33 | public synchronized String getM_BGUnits() { 34 | return m_BGUnits; 35 | } 36 | 37 | /** 38 | * @param m_BGUnits the m_BGUnits to set 39 | */ 40 | public synchronized void setM_BGUnits(String m_BGUnits) { 41 | this.m_BGUnits = m_BGUnits; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/control/ThreadAutotuneRemoteSaveAs.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.io.IOException; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | 7 | import miscellaneous.RemoteLinuxServer; 8 | 9 | public class ThreadAutotuneRemoteSaveAs extends ThreadAutotune 10 | { 11 | private static final Logger m_Logger = Logger.getLogger( MyLogger.class.getName() ); 12 | 13 | private String m_JSON; 14 | private String m_LocalFile; 15 | 16 | public ThreadAutotuneRemoteSaveAs(RemoteLinuxServer autoTuner, 17 | String json, String localFile) 18 | { 19 | super(autoTuner); 20 | m_JSON = new String(json); 21 | m_LocalFile = new String(localFile); 22 | } 23 | 24 | @Override 25 | protected void doAutotuneTask() 26 | { 27 | // TODO Auto-generated method stub 28 | try 29 | { 30 | m_Autotuner.remoteSaveAs(m_JSON, m_LocalFile); 31 | } 32 | catch (IOException e) 33 | { 34 | m_Logger.log(Level.SEVERE, "ThreadAutotuneRemoteSaveAs.doAutotuneTask exception caught " + e.getMessage()); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/control/ThreadAutotuneDownloadBackups.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.io.IOException; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | 7 | import miscellaneous.RemoteLinuxServer; 8 | 9 | public class ThreadAutotuneDownloadBackups extends ThreadAutotune 10 | { 11 | protected static final Logger m_Logger = Logger.getLogger( MyLogger.class.getName() ); 12 | 13 | private String m_LocalDirectory; 14 | 15 | public ThreadAutotuneDownloadBackups(RemoteLinuxServer autoTuner, String localDirectory) 16 | { 17 | super(autoTuner); 18 | m_LocalDirectory = new String(localDirectory); 19 | } 20 | 21 | @Override 22 | protected void doAutotuneTask() 23 | { 24 | // TODO Auto-generated method stub 25 | m_Autotuner.downloadAllBackupProfileFiles(m_LocalDirectory); 26 | try 27 | { 28 | Runtime.getRuntime().exec("explorer.exe /select," + m_LocalDirectory); 29 | } 30 | catch (IOException e) 31 | { 32 | m_Logger.log( Level.SEVERE, "ThreadAutotuneDownloadBackups caught exception " + e.getMessage() ); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/miscellaneous/BinaryFileFieldValue.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | //package org.DavidRichardson.NightscoutLoaderMaven; 3 | // 4 | //public class BinaryFileFieldValue 5 | //{ 6 | // enum BinaryFileFieldValueType 7 | // { 8 | // fvt_Unknown, 9 | // 10 | // fvt_IntVal, 11 | // fvt_ShortVal, 12 | // fvt_ByteVal, 13 | // fvt_StringVal, 14 | // fvt_FloatVal, 15 | // }; 16 | // 17 | // private byte[] m_OmniPodBytes = null; 18 | // private int m_Offset = 0; 19 | // private String m_FieldName = ""; 20 | // private BinaryStruct.VarType m_VarType = BinaryStruct.VarType.vt_Unknown; 21 | // private BinaryFileFieldValueType m_FieldType = BinaryFileFieldValueType.fvt_Unknown; 22 | // 23 | // private int m_IntVal = 0; 24 | // private short m_ShortVal = 0; 25 | // private byte m_ByteVal = 0; 26 | // private String m_StringVal = ""; 27 | // private float m_FloatVal = 0; 28 | // 29 | // 30 | // BinaryFileFieldValue(int offset, byte[] omniPodBytes, BinaryStruct.VarType varType) 31 | // { 32 | // 33 | // } 34 | // 35 | // 36 | // 37 | //} 38 | -------------------------------------------------------------------------------- /src/main/java/entity/ResultFromDBComparator.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import java.util.Comparator; 4 | 5 | public class ResultFromDBComparator implements Comparator 6 | { 7 | private boolean m_DescendingSort = true; 8 | public ResultFromDBComparator() 9 | { 10 | m_DescendingSort = true; 11 | } 12 | public ResultFromDBComparator(boolean descendingSort) 13 | { 14 | m_DescendingSort = descendingSort; 15 | } 16 | 17 | public int compare(DBResultInterface p1, DBResultInterface p2) 18 | { 19 | int result = 0; 20 | long p1_millies = p1.getM_EpochMillies(); 21 | long p2_millies = p2.getM_EpochMillies(); 22 | long diff = p1_millies - p2_millies; 23 | 24 | // Subtraction is too big for int result 25 | if ((diff) > 0) 26 | { 27 | // 1 to get results in ascending order 28 | // -1 to get results in descending order 29 | result = m_DescendingSort ? -1 : 1; 30 | } 31 | else if ((diff) < 0) 32 | { 33 | // -1 to get results in ascending order 34 | // 1 to get results in descending order 35 | result = m_DescendingSort ? 1 : -1; 36 | } 37 | return result; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/loader/AuditLogComparator.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | 3 | import java.util.Comparator; 4 | import java.util.Date; 5 | 6 | public class AuditLogComparator implements Comparator 7 | { 8 | private boolean m_DescendingSort = true; 9 | AuditLogComparator() 10 | { 11 | m_DescendingSort = true; 12 | } 13 | public AuditLogComparator(boolean descendingSort) 14 | { 15 | m_DescendingSort = descendingSort; 16 | } 17 | 18 | public int compare(AuditLog p1, AuditLog p2) 19 | { 20 | int result = 0; 21 | 22 | Date alD1 = p1.getM_UploadDate(); 23 | Date alD2 = p2.getM_UploadDate(); 24 | 25 | long p1_millies = alD1.getTime(); 26 | long p2_millies = alD2.getTime(); 27 | long diff = p1_millies - p2_millies; 28 | 29 | // Subtraction is too big for int result 30 | if ((diff) > 0) 31 | { 32 | // 1 to get results in ascending order 33 | // -1 to get results in descending order 34 | result = m_DescendingSort ? -1 : 1; 35 | } 36 | else if ((diff) < 0) 37 | { 38 | // -1 to get results in ascending order 39 | // 1 to get results in descending order 40 | result = m_DescendingSort ? 1 : -1; 41 | } 42 | return result; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bin/loadDiasend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Linux script to run NightScoutLoader to load all Diasend files from the $inDir 5 | # in succession, one after the other. 6 | # As each file gets processed, the file is moved to $arDir archive directory and 7 | # timestamped with processing date/time 8 | # 9 | # Variables below need to be set carefully 10 | # 11 | 12 | dir="" # Directory of the NightScoutLoader.jar file and probably this script too 13 | inDir="" # Directory where Diasend files to upload are put 14 | arDir="" # Directory where Diasend files once processed get archived 15 | log="${dir}/loadDiasend.log" 16 | jarLog="${dir}/NightscoutLoader_Diasend.log" 17 | jar="${dir}/NightScoutLoader.jar" 18 | msr="" # Set to your MongoDB URI 19 | mdb="" # Set to your MongoDB DB 20 | weeks=104 21 | 22 | processFile() 23 | { 24 | file=$1 25 | ofile=`basename "${file}" .xls`.`echo $(date +%FT%H%M%S)`.xls 26 | 27 | echo "$(date +%FT%H%M%S) - Processing Diasend file $file" | tee -a $log 28 | java -Xmx1024m -Xms128m -jar $jar -m diasend -f "${file}" -s $msr -d $mdb -w $weeks -l "$jarLog" | tee -a $log 29 | echo "Archiving file as $ofile in $arDir" 30 | mv "${file}" "${arDir}/${ofile}" 31 | } 32 | 33 | for f in ${inDir}/*; 34 | do 35 | processFile "$f" 36 | done 37 | -------------------------------------------------------------------------------- /bin/loadLibreview.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Linux script to run NightScoutLoader to load all LibreView files from the $inDir 5 | # in succession, one after the other. 6 | # As each file gets processed, the file is moved to $arDir archive directory and 7 | # timestamped with processing date/time 8 | # 9 | # Variables below need to be set carefully 10 | # 11 | 12 | dir="" # Directory of the NightScoutLoader.jar file and probably this script too 13 | inDir="" # Directory where LibreView files to upload are put 14 | arDir="" # Directory where LibreView files once processed get archived 15 | log="${dir}/loadLibreview.log" 16 | jarLog="${dir}/NightscoutLoader_Libre.log" 17 | jar="${dir}/NightScoutLoader.jar" 18 | msr="" # Set to your MongoDB URI 19 | mdb="" # Set to your MongoDB DB 20 | weeks=104 21 | 22 | processFile() 23 | { 24 | file=$1 25 | ofile=`basename "${file}" .csv`.`echo $(date +%FT%H%M%S)`.csv 26 | 27 | echo "$(date +%FT%H%M%S) - Processing Libreview file $file" | tee -a $log 28 | java -Xmx1024m -Xms128m -jar $jar -m libreview -f "${file}" -s $msr -d $mdb -w $weeks -l "$jarLog" | tee -a $log 29 | echo "Archiving file as $ofile in $arDir" 30 | mv "${file}" "${arDir}/${ofile}" 31 | } 32 | 33 | for f in ${inDir}/*; 34 | do 35 | processFile "$f" 36 | done 37 | -------------------------------------------------------------------------------- /src/main/java/miscellaneous/OmniPodBinaryFileSectionComparator.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | 3 | import java.util.Comparator; 4 | //import java.util.Date; 5 | 6 | public class OmniPodBinaryFileSectionComparator implements Comparator 7 | { 8 | 9 | private boolean m_DescendingSort = true; 10 | OmniPodBinaryFileSectionComparator() 11 | { 12 | m_DescendingSort = true; 13 | } 14 | OmniPodBinaryFileSectionComparator(boolean descendingSort) 15 | { 16 | m_DescendingSort = descendingSort; 17 | } 18 | 19 | public int compare(OmniPodBinaryFileSection p1, OmniPodBinaryFileSection p2) 20 | { 21 | int result = 0; 22 | 23 | String alD1 = p1.getM_SectionHeader(); 24 | String alD2 = p2.getM_SectionHeader(); 25 | 26 | int hash1 = alD1.hashCode(); 27 | int hash2 = alD2.hashCode(); 28 | int diff = hash1 - hash2; 29 | 30 | // Subtraction is too big for int result 31 | if ((diff) > 0) 32 | { 33 | // 1 to get results in ascending order 34 | // -1 to get results in descending order 35 | result = m_DescendingSort ? -1 : 1; 36 | } 37 | else if ((diff) < 0) 38 | { 39 | // -1 to get results in ascending order 40 | // 1 to get results in descending order 41 | result = m_DescendingSort ? 1 : -1; 42 | } 43 | return result; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultPumpSettingTarget.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import org.apache.poi.hssf.usermodel.HSSFRow; 4 | 5 | public class DBResultPumpSettingTarget extends DBResultPumpSetting 6 | { 7 | private String m_BGUnits; 8 | private Double m_TargetLowValue; 9 | private Double m_TargetHighValue; 10 | 11 | public DBResultPumpSettingTarget(HSSFRow row, String bgUnits) 12 | { 13 | super(row); 14 | 15 | m_BGUnits = new String(bgUnits); 16 | } 17 | 18 | /** 19 | * @return the m_BGUnits 20 | */ 21 | public synchronized String getM_BGUnits() { 22 | return m_BGUnits; 23 | } 24 | 25 | /** 26 | * @param m_BGUnits the m_BGUnits to set 27 | */ 28 | public synchronized void setM_BGUnits(String m_BGUnits) { 29 | this.m_BGUnits = m_BGUnits; 30 | } 31 | 32 | /** 33 | * @return the m_TargetLowValue 34 | */ 35 | public synchronized Double getM_TargetLowValue() { 36 | return m_TargetLowValue; 37 | } 38 | 39 | /** 40 | * @param m_TargetLowValue the m_TargetLowValue to set 41 | */ 42 | public synchronized void setM_TargetLowValue(Double m_TargetLowValue) { 43 | this.m_TargetLowValue = m_TargetLowValue; 44 | } 45 | 46 | /** 47 | * @return the m_TargetHighValue 48 | */ 49 | public synchronized Double getM_TargetHighValue() { 50 | return m_TargetHighValue; 51 | } 52 | 53 | /** 54 | * @param m_TargetHighValue the m_TargetHighValue to set 55 | */ 56 | public synchronized void setM_TargetHighValue(Double m_TargetHighValue) { 57 | this.m_TargetHighValue = m_TargetHighValue; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/analysis/AnalyzerEntriesCGMDay.java: -------------------------------------------------------------------------------- 1 | package analysis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | import control.MyLogger; 9 | import entity.DBResultEntry; 10 | 11 | public class AnalyzerEntriesCGMDay 12 | { 13 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 14 | 15 | private static Integer m_Static_ID = 0; // Assign an ID to each result created. 16 | private int m_ID = 0; // Assign an ID to each result created. 17 | 18 | private Date m_Date; 19 | private ArrayList m_DBResultEntries; 20 | 21 | AnalyzerEntriesCGMDay(Date date) 22 | { 23 | m_Static_ID++; 24 | m_ID = m_Static_ID; 25 | 26 | m_Logger.log(Level.FINE, "Just built AnalyzerEntriesCGMDay " + m_ID + " @" + 27 | date.toString()); 28 | 29 | 30 | m_Date = new Date(date.getTime()); 31 | m_DBResultEntries = new ArrayList(); 32 | } 33 | 34 | public void addDBResultEntry(DBResultEntry e) 35 | { 36 | m_DBResultEntries.add(e); 37 | } 38 | 39 | public synchronized static void resetStaticID() 40 | { 41 | m_Static_ID = 0; 42 | } 43 | 44 | /** 45 | * @return the m_ID 46 | */ 47 | public synchronized int getM_ID() { 48 | return m_ID; 49 | } 50 | 51 | 52 | /** 53 | * @return the m_Date 54 | */ 55 | public synchronized Date getM_Date() { 56 | return m_Date; 57 | } 58 | 59 | /** 60 | * @return the m_DBResultEntries 61 | */ 62 | public synchronized ArrayList getM_DBResultEntries() { 63 | return m_DBResultEntries; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/miscellaneous/DateLabelFormatter.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Calendar; 6 | import java.util.Date; 7 | 8 | import javax.swing.JFormattedTextField.AbstractFormatter; 9 | 10 | // Used to format dates in JDatePicker 11 | public class DateLabelFormatter extends AbstractFormatter 12 | { 13 | 14 | /** 15 | * 16 | */ 17 | private static final long serialVersionUID = 1L; 18 | 19 | private String datePattern = "dd-MMM-yyyy"; 20 | private SimpleDateFormat dateFormatter = new SimpleDateFormat(datePattern); 21 | 22 | @Override 23 | public Object stringToValue(String text) throws ParseException { 24 | return dateFormatter.parseObject(text); 25 | } 26 | 27 | @Override 28 | public String valueToString(Object value) throws ParseException { 29 | if (value != null) 30 | { 31 | // Date dateVal = (Date)value; 32 | // return dateFormatter.format(dateVal.getTime()); 33 | 34 | if (value.getClass().getName().equals("java.util.GregorianCalendar")) 35 | { 36 | // David - 30 Aug 2016 37 | Calendar cal = (Calendar)value; // Get exception about casting a Date to Calendar 38 | // Seems to happen on analyzer when setting days back, clicking off then running analyze 39 | return dateFormatter.format(cal.getTime()); 40 | } 41 | else if (value.getClass().getName().equals("java.util.Date")) 42 | { 43 | // David - 30 Aug 2016 44 | Date cal = (Date)value; // Get exception about casting a Date to Calendar 45 | // Seems to happen on analyzer when setting days back, clicking off then running analyze 46 | return dateFormatter.format(cal.getTime()); 47 | } 48 | else 49 | { 50 | System.out.println("Unexpected Class type here " + value.getClass().getName()); 51 | } 52 | } 53 | 54 | return ""; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/miscellaneous/OmniPodValidator.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | 3 | public abstract class OmniPodValidator 4 | { 5 | // private OmniPodBinaryFileSection m_OmniPodBinaryFileSection; 6 | 7 | public class OmniPodDetails 8 | { 9 | 10 | }; 11 | 12 | // -------------------------------- 13 | // Class for handling Bolus details 14 | // -------------------------------- 15 | public class OmniPodDetailsBolus extends OmniPodDetails 16 | { 17 | private int m_VolumeUnits = 0; 18 | private int m_ExtendedDurationMSec = 0; 19 | private int m_ImmediateDurationMSec = 0; 20 | /** 21 | * @return the m_VolumeUnits 22 | */ 23 | public synchronized int getM_VolumeUnits() { 24 | return m_VolumeUnits; 25 | } 26 | /** 27 | * @param m_VolumeUnits the m_VolumeUnits to set 28 | */ 29 | public synchronized void setM_VolumeUnits(int m_VolumeUnits) { 30 | this.m_VolumeUnits = m_VolumeUnits; 31 | } 32 | /** 33 | * @return the m_ExtendedDurationMSec 34 | */ 35 | public synchronized int getM_ExtendedDurationMSec() { 36 | return m_ExtendedDurationMSec; 37 | } 38 | /** 39 | * @param m_ExtendedDurationMSec the m_ExtendedDurationMSec to set 40 | */ 41 | public synchronized void setM_ExtendedDurationMSec(int m_ExtendedDurationMSec) { 42 | this.m_ExtendedDurationMSec = m_ExtendedDurationMSec; 43 | } 44 | /** 45 | * @return the m_ImmediateDurationMSec 46 | */ 47 | public synchronized int getM_ImmediateDurationMSec() { 48 | return m_ImmediateDurationMSec; 49 | } 50 | /** 51 | * @param m_ImmediateDurationMSec the m_ImmediateDurationMSec to set 52 | */ 53 | public synchronized void setM_ImmediateDurationMSec(int m_ImmediateDurationMSec) { 54 | this.m_ImmediateDurationMSec = m_ImmediateDurationMSec; 55 | } 56 | }; 57 | 58 | public abstract boolean valid(); 59 | public abstract OmniPodDetails getDetails(); 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultPumpSetting.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import org.apache.poi.hssf.usermodel.HSSFCell; 4 | import org.apache.poi.hssf.usermodel.HSSFRow; 5 | import org.apache.poi.ss.usermodel.Cell; 6 | 7 | public class DBResultPumpSetting 8 | { 9 | private int m_Index; 10 | private String m_Time; 11 | private Double m_TimeBoundValue; 12 | 13 | private final int m_SettingsFields = 3; 14 | 15 | // Utility Function for getting a cell from row as string even if numeric 16 | public static String getCellAsString(HSSFRow row, int index) 17 | { 18 | String result = ""; 19 | Cell cell = row.getCell(index); 20 | if (cell != null) 21 | { 22 | // Check type of this cell first 23 | if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) 24 | { 25 | result = cell.getStringCellValue(); 26 | } 27 | else 28 | { 29 | Double result_num = cell.getNumericCellValue(); 30 | result = result_num.toString(); 31 | } 32 | } 33 | return result; 34 | } 35 | 36 | DBResultPumpSetting(HSSFRow row) 37 | { 38 | int maxColumns = row.getPhysicalNumberOfCells(); 39 | if (maxColumns == m_SettingsFields) 40 | { 41 | Double cell1 = row.getCell(0).getNumericCellValue(); 42 | String cell2 = row.getCell(1).getStringCellValue(); 43 | Double cell3 = row.getCell(2).getNumericCellValue(); 44 | 45 | m_Index = cell1.intValue(); 46 | m_Time = cell2; 47 | m_TimeBoundValue = cell3; 48 | } 49 | } 50 | 51 | public String toString() 52 | { 53 | return String.format("Index: %d, Time: %s, Value: %g", 54 | m_Index, m_Time, m_TimeBoundValue); 55 | } 56 | 57 | /** 58 | * @return the m_Index 59 | */ 60 | public synchronized int getM_Index() { 61 | return m_Index; 62 | } 63 | 64 | /** 65 | * @param m_Index the m_Index to set 66 | */ 67 | public synchronized void setM_Index(int m_Index) { 68 | this.m_Index = m_Index; 69 | } 70 | 71 | /** 72 | * @return the m_Time 73 | */ 74 | public synchronized String getM_Time() { 75 | return m_Time; 76 | } 77 | 78 | /** 79 | * @param m_Time the m_Time to set 80 | */ 81 | public synchronized void setM_Time(String m_Time) { 82 | this.m_Time = m_Time; 83 | } 84 | 85 | /** 86 | * @return the m_TimeBoundValue 87 | */ 88 | public synchronized Double getM_TimeBoundValue() { 89 | return m_TimeBoundValue; 90 | } 91 | 92 | /** 93 | * @param m_TimeBoundValue the m_TimeBoundValue to set 94 | */ 95 | public synchronized void setM_TimeBoundValue(Double m_TimeBoundValue) { 96 | this.m_TimeBoundValue = m_TimeBoundValue; 97 | } 98 | 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/control/MainNightScoutLoader.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.awt.EventQueue; 4 | import java.io.IOException; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | import win.WinNightScoutLoader; 9 | 10 | public class MainNightScoutLoader implements MainControlInterface 11 | { 12 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 13 | // private static final MyLogger m_MyLogger = new MyLogger(true); 14 | 15 | private CommandLineHandlerSingleThreaded commandLineHandler; 16 | // private CommandLineHandlerMultiThreaded commandLineHandler; 17 | 18 | public MainNightScoutLoader(String[] args) 19 | { 20 | commandLineHandler = new CommandLineHandlerSingleThreaded(args, this); 21 | // commandLineHandler = new CommandLineHandlerMultiThreaded(args, this); 22 | } 23 | 24 | /** 25 | * Launch the application. 26 | */ 27 | public static void main(String[] args) 28 | { 29 | // Initialise the Logging mechanism. 30 | try 31 | { 32 | Boolean consolLoggingBoolean = args == null || args.length == 0 ? false : true; 33 | 34 | MyLogger.setup(consolLoggingBoolean); 35 | } 36 | catch (IOException e1) 37 | { 38 | // Can;t use the logging mechanism, so simply output to SYSTEM 39 | // TODO Auto-generated catch block 40 | e1.printStackTrace(); 41 | } 42 | 43 | MainNightScoutLoader mainNightScoutLoader = new MainNightScoutLoader(args); 44 | 45 | if (mainNightScoutLoader.commandLineHandler.launchWindow()) 46 | { 47 | mainNightScoutLoader.launchWindow(); 48 | } 49 | else 50 | { 51 | mainNightScoutLoader.launchCommandLineLoader(); 52 | } 53 | } 54 | 55 | private void launchWindow() 56 | { 57 | EventQueue.invokeLater(new Runnable() 58 | { 59 | public void run() 60 | { 61 | try 62 | { 63 | //http://stackoverflow.com/questions/7612592/jframe-and-nimbus-look-and-feel 64 | // JFrame.setDefaultLookAndFeelDecorated(true); //before creating JFrames 65 | 66 | WinNightScoutLoader mainWin; 67 | mainWin = new WinNightScoutLoader(); 68 | mainWin.setVisible(true); 69 | } 70 | catch (Exception e) 71 | { 72 | m_Logger.log(Level.SEVERE, "<"+this.getClass().getName()+">" + "Main: unhandled exception " + e.getLocalizedMessage()); 73 | System.out.println("SEVERE ERROR : " + e.getLocalizedMessage()); 74 | } 75 | } 76 | }); 77 | } 78 | 79 | private void launchCommandLineLoader() 80 | { 81 | commandLineHandler.runWithoutWindow(); 82 | } 83 | 84 | @Override 85 | public void shutdown() 86 | { 87 | m_Logger.log(Level.INFO, "Operation complete. Shutting down"); 88 | 89 | Runtime rtRuntime = Runtime.getRuntime(); 90 | rtRuntime.exit(0); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/win/WinAbout.java: -------------------------------------------------------------------------------- 1 | package win; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.FlowLayout; 5 | import java.awt.Font; 6 | 7 | import javax.swing.ImageIcon; 8 | import javax.swing.JButton; 9 | import javax.swing.JDialog; 10 | import javax.swing.JPanel; 11 | import javax.swing.border.EmptyBorder; 12 | 13 | import control.MainNightScoutLoader; 14 | 15 | import javax.swing.JTextArea; 16 | import java.awt.event.ActionListener; 17 | import java.net.URL; 18 | import java.awt.event.ActionEvent; 19 | import javax.swing.JScrollPane; 20 | import control.Version; 21 | 22 | public class WinAbout extends JDialog { 23 | 24 | /** 25 | * 26 | */ 27 | private static final long serialVersionUID = -51832866421758739L; 28 | 29 | private final JPanel contentPanel = new JPanel(); 30 | 31 | private String m_AboutText; 32 | 33 | /** 34 | * Create the dialog. 35 | */ 36 | public WinAbout(String title) 37 | { 38 | super.setTitle(title); 39 | 40 | URL url = MainNightScoutLoader.class.getResource("/Nightscout.jpg"); 41 | ImageIcon img = new ImageIcon(url); 42 | setIconImage(img.getImage()); 43 | 44 | m_AboutText = new String(); 45 | 46 | m_AboutText = Version.getInstance().getM_AboutText(); 47 | 48 | setBounds(100, 100, 750, 600); 49 | getContentPane().setLayout(new BorderLayout()); 50 | contentPanel.setLayout(new FlowLayout()); 51 | contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); 52 | getContentPane().add(contentPanel, BorderLayout.CENTER); 53 | 54 | JPanel buttonPane = new JPanel(); 55 | buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); 56 | getContentPane().add(buttonPane, BorderLayout.SOUTH); 57 | { 58 | JButton okButton = new JButton("OK"); 59 | okButton.addActionListener(new ActionListener() { 60 | public void actionPerformed(ActionEvent arg0) { 61 | setVisible(false); 62 | } 63 | }); 64 | okButton.setActionCommand("OK"); 65 | buttonPane.add(okButton); 66 | getRootPane().setDefaultButton(okButton); 67 | } 68 | { 69 | JButton cancelButton = new JButton("Cancel"); 70 | cancelButton.addActionListener(new ActionListener() { 71 | public void actionPerformed(ActionEvent arg0) { 72 | setVisible(false); 73 | } 74 | }); 75 | cancelButton.setActionCommand("Cancel"); 76 | buttonPane.add(cancelButton); 77 | } 78 | 79 | Font font = new Font("Courier", Font.BOLD, 12); 80 | 81 | 82 | JTextArea txtrNightscoutloader = new JTextArea(); 83 | getContentPane().add(txtrNightscoutloader, BorderLayout.WEST); 84 | txtrNightscoutloader.setFont(font); 85 | 86 | txtrNightscoutloader.setText(m_AboutText); 87 | 88 | JScrollPane scrollPane = new JScrollPane(txtrNightscoutloader); 89 | getContentPane().add(scrollPane, BorderLayout.CENTER); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/miscellaneous/BinaryFileFieldAccess.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.ByteOrder; 5 | 6 | public class BinaryFileFieldAccess 7 | { 8 | // private byte[] m_RawData = null; 9 | 10 | BinaryFileFieldAccess(byte[] rawdata) 11 | { 12 | // m_RawData = rawdata; 13 | } 14 | 15 | public int extractInt(byte[] rawdata, int offset) 16 | { 17 | int result = ByteBuffer.wrap(rawdata,offset,4).order(ByteOrder.LITTLE_ENDIAN).getInt(); 18 | return result; 19 | } 20 | public int extractSignedInt(byte[] rawdata, int offset) 21 | { 22 | int result = extractInt(rawdata, offset); 23 | return result; 24 | } 25 | 26 | public short extractShort(byte[] rawdata, int offset) 27 | { 28 | short result = ByteBuffer.wrap(rawdata,offset,4).order(ByteOrder.LITTLE_ENDIAN).getShort(); 29 | return result; 30 | } 31 | public short extractSignedShort(byte[] rawdata, int offset) 32 | { 33 | short result = extractShort(rawdata, offset); 34 | return result; 35 | } 36 | 37 | public byte extractbyte(byte[] rawdata, int offset) 38 | { 39 | return rawdata[offset]; 40 | } 41 | 42 | public byte extractSignedbyte(byte[] rawdata, int offset) 43 | { 44 | byte result = extractbyte(rawdata, offset); 45 | 46 | result = (byte) ((result & 127) - (result & 128)); 47 | return result; 48 | } 49 | 50 | public String extractbytes(byte[] rawdata, int offset, int len) 51 | { 52 | String result = new String(); 53 | for (int c = offset; c < offset + len; c++) 54 | { 55 | result += rawdata[c]; 56 | } 57 | 58 | return result; 59 | } 60 | 61 | public float extractFloat(byte[] rawdata, int offset) 62 | { 63 | float result = ByteBuffer.wrap(rawdata,offset,4).order(ByteOrder.LITTLE_ENDIAN).getFloat(); 64 | return result; 65 | } 66 | 67 | public int extractBEInt(byte[] rawdata, int offset) 68 | { 69 | int result = ByteBuffer.wrap(rawdata,offset,4).order(ByteOrder.BIG_ENDIAN).getInt(); 70 | return result; 71 | } 72 | 73 | public int extractBESignedInt(byte[] rawdata, int offset) 74 | { 75 | int result = extractBEInt(rawdata, offset); 76 | return result; 77 | } 78 | 79 | public short extractBEShort(byte[] rawdata, int offset) 80 | { 81 | short result = ByteBuffer.wrap(rawdata,offset,4).order(ByteOrder.BIG_ENDIAN).getShort(); 82 | return result; 83 | } 84 | 85 | public short extractBESignedShort(byte[] rawdata, int offset) 86 | { 87 | short result = extractBEShort(rawdata, offset); 88 | return result; 89 | } 90 | 91 | public String extractZString(byte[] rawdata, int offset, int len) 92 | { 93 | String result = extractbytes(rawdata, offset, len); 94 | return result; 95 | } 96 | public String extractString(byte[] rawdata, int offset, int len) 97 | { 98 | String result = extractbytes(rawdata, offset, len); 99 | return result; 100 | } 101 | } 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/main/java/miscellaneous/OmniPodBinaryFileSection.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class OmniPodBinaryFileSection 6 | { 7 | protected String m_SectionHeader; 8 | protected String m_Encoding; 9 | protected ArrayList m_FieldNames; 10 | protected ArrayList m_FieldValues; 11 | protected OmniPodValidator m_Validator = null; 12 | 13 | public OmniPodBinaryFileSection(String sectionHeader, String encoding, String[] fieldNames) 14 | { 15 | m_SectionHeader = new String(sectionHeader); 16 | m_Encoding = new String(encoding); 17 | m_FieldNames = new ArrayList(); 18 | m_FieldValues = new ArrayList(); 19 | 20 | if (fieldNames != null) 21 | { 22 | for (String f : fieldNames) 23 | { 24 | m_FieldNames.add(f); 25 | } 26 | } 27 | } 28 | 29 | public OmniPodBinaryFileSection(String sectionHeader, String encoding, 30 | String[] fieldNames, 31 | OmniPodValidator validator) 32 | { 33 | m_SectionHeader = new String(sectionHeader); 34 | m_Encoding = new String(encoding); 35 | m_FieldNames = new ArrayList(); 36 | m_FieldValues = new ArrayList(); 37 | 38 | for (String f : fieldNames) 39 | { 40 | m_FieldNames.add(f); 41 | } 42 | m_Validator = validator; 43 | } 44 | 45 | public OmniPodBinaryFileSection(String sectionHeader, String encoding, 46 | String[] fieldNames, String[] fieldValues) 47 | { 48 | m_SectionHeader = new String(sectionHeader); 49 | m_Encoding = new String(encoding); 50 | m_FieldNames = new ArrayList(); 51 | m_FieldValues = new ArrayList(); 52 | 53 | for (String f : fieldNames) 54 | { 55 | m_FieldNames.add(f); 56 | } 57 | for (String f : fieldValues) 58 | { 59 | m_FieldValues.add(f); 60 | } 61 | } 62 | 63 | public OmniPodBinaryFileSection(String sectionHeader, String encoding, 64 | String[] fieldNames, String[] fieldValues, 65 | OmniPodValidator validator) 66 | { 67 | m_SectionHeader = new String(sectionHeader); 68 | m_Encoding = new String(encoding); 69 | m_FieldNames = new ArrayList(); 70 | m_FieldValues = new ArrayList(); 71 | 72 | for (String f : fieldNames) 73 | { 74 | m_FieldNames.add(f); 75 | } 76 | for (String f : fieldValues) 77 | { 78 | m_FieldValues.add(f); 79 | } 80 | m_Validator = validator; 81 | } 82 | 83 | /** 84 | * @return the m_SectionHeader 85 | */ 86 | public synchronized String getM_SectionHeader() { 87 | return m_SectionHeader; 88 | } 89 | 90 | /** 91 | * @param m_SectionHeader the m_SectionHeader to set 92 | */ 93 | public synchronized void setM_SectionHeader(String m_SectionHeader) { 94 | this.m_SectionHeader = m_SectionHeader; 95 | } 96 | 97 | /** 98 | * @return the m_Encoding 99 | */ 100 | public synchronized String getM_Encoding() { 101 | return m_Encoding; 102 | } 103 | 104 | /** 105 | * @param m_Encoding the m_Encoding to set 106 | */ 107 | public synchronized void setM_Encoding(String m_Encoding) { 108 | this.m_Encoding = m_Encoding; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/analysis/AnalyzerTrendResultEntryComparator.java: -------------------------------------------------------------------------------- 1 | package analysis; 2 | 3 | import java.util.Comparator; 4 | 5 | import analysis.AnalyzerResultEntryInterval.DBResultEntryProfileDirection; 6 | 7 | 8 | public class AnalyzerTrendResultEntryComparator implements Comparator 9 | { 10 | private boolean m_DescendingSort = true; 11 | private AnalyzerTrendResultEntryComparatorType m_CompType = AnalyzerTrendResultEntryComparatorType.NumericSort; 12 | 13 | public enum AnalyzerTrendResultEntryComparatorType 14 | { 15 | NumericSort, 16 | TimeSort, 17 | TypeSort, 18 | }; 19 | 20 | AnalyzerTrendResultEntryComparator() 21 | { 22 | m_DescendingSort = true; 23 | } 24 | AnalyzerTrendResultEntryComparator(boolean descendingSort) 25 | { 26 | m_DescendingSort = descendingSort; 27 | } 28 | AnalyzerTrendResultEntryComparator(boolean descendingSort, 29 | AnalyzerTrendResultEntryComparatorType compType) 30 | { 31 | m_DescendingSort = descendingSort; 32 | m_CompType = compType; 33 | } 34 | 35 | public int compare(AnalyzerTrendResultEntry p1, AnalyzerTrendResultEntry p2) 36 | { 37 | int result = 0; 38 | 39 | int p1_entries = p1.getM_ResultEntryIntervals().size(); 40 | int p2_entries = p2.getM_ResultEntryIntervals().size(); 41 | 42 | // DBResultEntryProfileChange p1_profile = p1.getM_DBResultEntryProfileChange(); 43 | // DBResultEntryProfileChange p2_profile = p2.getM_DBResultEntryProfileChange(); 44 | 45 | DBResultEntryProfileDirection p1_direction = p1.getM_ProfileDirection(); 46 | DBResultEntryProfileDirection p2_direction = p2.getM_ProfileDirection(); 47 | 48 | 49 | // Subtraction is too big for int result 50 | long diff = p1_entries - p2_entries; 51 | int timeDiff = p1.getM_StartHour() - p2.getM_StartHour(); 52 | int profileDiff = p1_direction.hashCode() - p2_direction.hashCode(); // this will do 53 | 54 | // Sort based on number of entries and then also by time 55 | if ( // Numeric Sort 56 | (m_CompType == AnalyzerTrendResultEntryComparatorType.NumericSort 57 | && (diff > 0) || (diff == 0 && timeDiff < 0) ) 58 | 59 | || 60 | // Time Sort 61 | ((m_CompType == AnalyzerTrendResultEntryComparatorType.TimeSort 62 | && timeDiff < 0)) 63 | 64 | || 65 | // Type Sort 66 | ((m_CompType == AnalyzerTrendResultEntryComparatorType.TypeSort 67 | && profileDiff < 0)) 68 | ) 69 | { 70 | // 1 to get results in ascending order 71 | // -1 to get results in descending order 72 | result = m_DescendingSort ? -1 : 1; 73 | } 74 | // else if ( (diff < 0) || (diff == 0 && timeDiff > 0) ) 75 | else if ( // Numeric Sort 76 | (m_CompType == AnalyzerTrendResultEntryComparatorType.NumericSort 77 | && (diff < 0) || (diff == 0 && timeDiff > 0) ) 78 | 79 | || 80 | // Time Sort 81 | ((m_CompType == AnalyzerTrendResultEntryComparatorType.TimeSort 82 | && timeDiff > 0)) 83 | 84 | || 85 | // Type Sort 86 | ((m_CompType == AnalyzerTrendResultEntryComparatorType.TypeSort 87 | && profileDiff < 0)) 88 | ) 89 | 90 | { 91 | // -1 to get results in ascending order 92 | // 1 to get results in descending order 93 | result = m_DescendingSort ? 1 : -1; 94 | } 95 | 96 | return result; 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/test/java/loader/TestDiasendTreatmentInsCarbNotMerged.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | 3 | import java.text.SimpleDateFormat; 4 | 5 | import org.junit.jupiter.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.junit.MockitoJUnitRunner; 9 | 10 | @RunWith(MockitoJUnitRunner.class) 11 | public class TestDiasendTreatmentInsCarbNotMerged extends BaseTestTreatment { 12 | 13 | private static final String RESOURCE_FILE_NAME_STRING = "Sample_Diasend2.xls"; 14 | 15 | 16 | private static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm"); 17 | 18 | private static Object[][] EXPECTED_TREATMENT_RESULTS = 19 | { 20 | // Date of Reading BG INS CARBS DUPE? 21 | { "20/03/2021 19:01", 0.0, 6.80, 0.00, "NO"}, 22 | { "28/03/2021 15:41", 0.0, 4.05, 45.00, "YES"}, 23 | { "28/03/2021 15:41", 0.0, 4.05, 45.00, "NO"}, 24 | { "06/04/2021 00:00", 0.0, 1.30, 0.00, "NO"}, 25 | { "09/04/2021 00:00", 0.0, 1.60, 0.00, "NO"}, 26 | { "13/04/2021 19:44", 0.0, 5.00, 50.00, "YES"}, 27 | { "13/04/2021 19:44", 0.0, 5.00, 50.00, "NO"}, 28 | { "15/04/2021 00:00", 0.0, 2.70, 0.00, "NO"}, 29 | { "27/05/2021 00:00", 0.0, 0.95, 0.00, "NO"}, 30 | { "12/06/2021 00:00", 0.0, 3.05, 0.00, "NO"}, 31 | { "08/07/2021 20:44", 0.0, 4.00, 40.00, "YES"}, 32 | { "08/07/2021 20:44", 0.0, 4.00, 40.00, "NO"}, 33 | { "23/07/2021 00:00", 0.0, 0.35, 0.00, "NO"}, 34 | { "10/09/2021 00:00", 0.0, 0.95, 0.00, "NO"}, 35 | { "03/10/2021 17:45", 0.0, 3.15, 35.00, "YES"}, 36 | { "03/10/2021 17:45", 0.0, 3.15, 35.00, "NO"}, 37 | { "04/10/2021 11:52", 0.0, 4.05, 45.00, "YES"}, 38 | { "04/10/2021 11:52", 0.0, 4.05, 45.00, "NO"}, 39 | 40 | }; 41 | 42 | DataLoadFile dataLoadFile = new DataLoadDiasend(); 43 | 44 | @Test 45 | public void doTestLoad() 46 | { 47 | String nameofCurrMethod = new Throwable() 48 | .getStackTrace()[0] 49 | .getMethodName(); 50 | System.out.println("[INFO] *** TEST *** " + this.getClass().getSimpleName() + "." + nameofCurrMethod); 51 | performTestLoad(); 52 | } 53 | 54 | @Test 55 | public void doTestCount() 56 | { 57 | String nameofCurrMethod = new Throwable() 58 | .getStackTrace()[0] 59 | .getMethodName(); 60 | System.out.println("[INFO] *** TEST *** " + this.getClass().getSimpleName() + "." + nameofCurrMethod); 61 | doDataLoad(); 62 | 63 | int dlEntries = this.countDataLoadEntries(false); 64 | int exEntries = this.countExpectedResults(); 65 | 66 | Assertions.assertTrue( dlEntries == exEntries, "Expect record counts of entries without BG to match data set provided. " 67 | + dlEntries + " in data load, " 68 | + exEntries + " in data set provided."); 69 | } 70 | 71 | @Override 72 | protected Object[][] getExpectedTestResults() { 73 | return EXPECTED_TREATMENT_RESULTS; 74 | } 75 | 76 | @Override 77 | protected String getResourceFileName() { 78 | return RESOURCE_FILE_NAME_STRING; 79 | } 80 | 81 | @Override 82 | protected DataLoadFile getDataLoadFile() { 83 | return dataLoadFile; 84 | } 85 | 86 | @Override 87 | protected SimpleDateFormat getSimpleDateFormat() { 88 | return DATE_FORMAT; 89 | } 90 | 91 | @Override 92 | protected String getDateFormat() { 93 | return "dd/MM/yyyy HH:mm"; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/analysis/AnalyzerTrendResultEntryAggregate.java: -------------------------------------------------------------------------------- 1 | package analysis; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class AnalyzerTrendResultEntryAggregate 6 | { 7 | // David -- getting tired 8 | // Group these into a single class for easier access. 9 | // 16 Dec 2016 10 | 11 | private static Integer m_Static_ID = 0; // Assign an ID to each result created. 12 | private int m_ID = 0; // Assign an ID to each result created. 13 | 14 | private AnalyzerTrendResultAggregateGroup m_OffsetMinusTwoAggregateGroup; 15 | private AnalyzerTrendResultAggregateGroup m_OffsetMinusOneAggregateGroup; 16 | private AnalyzerTrendResultAggregateGroup m_NoOffsetAggregateGroup; 17 | private AnalyzerTrendResultAggregateGroup m_OffsetPlusOneAggregateGroup; 18 | private AnalyzerTrendResultAggregateGroup m_OffsetPlusTwoAggregateGroup; 19 | 20 | AnalyzerTrendResultEntryAggregate() 21 | { 22 | m_Static_ID++; 23 | m_ID = m_Static_ID; 24 | 25 | m_OffsetMinusTwoAggregateGroup = new AnalyzerTrendResultAggregateGroup(); 26 | m_OffsetMinusOneAggregateGroup = new AnalyzerTrendResultAggregateGroup(); 27 | m_NoOffsetAggregateGroup = new AnalyzerTrendResultAggregateGroup(); 28 | m_OffsetPlusOneAggregateGroup = new AnalyzerTrendResultAggregateGroup(); 29 | m_OffsetPlusTwoAggregateGroup = new AnalyzerTrendResultAggregateGroup(); 30 | } 31 | 32 | public void initialize(ArrayList trendResultEntries, 33 | ArrayList trendResultEntriesPlusOne, 34 | ArrayList trendResultEntriesPlusTwo, 35 | ArrayList trendResultEntriesMinusOne, 36 | ArrayList trendResultEntriesMinusTwo) 37 | { 38 | m_OffsetMinusTwoAggregateGroup.initialize(trendResultEntriesMinusTwo); 39 | m_OffsetMinusOneAggregateGroup.initialize(trendResultEntriesMinusOne); 40 | m_NoOffsetAggregateGroup.initialize(trendResultEntries); 41 | m_OffsetPlusOneAggregateGroup.initialize(trendResultEntriesPlusOne); 42 | m_OffsetPlusTwoAggregateGroup.initialize(trendResultEntriesPlusTwo); 43 | } 44 | 45 | public synchronized static void resetStaticID() 46 | { 47 | m_Static_ID = 0; 48 | } 49 | 50 | /** 51 | * @return the m_ID 52 | */ 53 | public synchronized int getM_ID() { 54 | return m_ID; 55 | } 56 | 57 | 58 | /** 59 | * @return the m_OffsetMinusTwoAggregateGroup 60 | */ 61 | public synchronized AnalyzerTrendResultAggregateGroup getM_OffsetMinusTwoAggregateGroup() { 62 | return m_OffsetMinusTwoAggregateGroup; 63 | } 64 | 65 | /** 66 | * @return the m_OffsetMinusOneAggregateGroup 67 | */ 68 | public synchronized AnalyzerTrendResultAggregateGroup getM_OffsetMinusOneAggregateGroup() { 69 | return m_OffsetMinusOneAggregateGroup; 70 | } 71 | 72 | /** 73 | * @return the m_NoOffsetAggregateGroup 74 | */ 75 | public synchronized AnalyzerTrendResultAggregateGroup getM_NoOffsetAggregateGroup() { 76 | return m_NoOffsetAggregateGroup; 77 | } 78 | 79 | /** 80 | * @return the m_OffsetPlusOneAggregateGroup 81 | */ 82 | public synchronized AnalyzerTrendResultAggregateGroup getM_OffsetPlusOneAggregateGroup() { 83 | return m_OffsetPlusOneAggregateGroup; 84 | } 85 | 86 | /** 87 | * @return the m_OffsetPlusTwoAggregateGroup 88 | */ 89 | public synchronized AnalyzerTrendResultAggregateGroup getM_OffsetPlusTwoAggregateGroup() { 90 | return m_OffsetPlusTwoAggregateGroup; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/control/ThreadHelpLauncher.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.awt.Desktop; 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.util.ArrayList; 9 | import java.util.logging.Level; 10 | import java.util.logging.Logger; 11 | 12 | public class ThreadHelpLauncher implements Runnable 13 | { 14 | private static final Logger m_Logger = Logger.getLogger( MyLogger.class.getName() ); 15 | 16 | // Separate thread for Analyzer to run 17 | private Thread m_HelpLauncherThread; 18 | 19 | private ArrayList m_RequestList = new ArrayList(); 20 | 21 | // static Object m_Lock = new Object(); 22 | private Object m_Lock; 23 | 24 | // Thread Synchronization 25 | public void waitUntilFree() 26 | { 27 | synchronized(m_Lock) 28 | { 29 | while (m_RequestList.isEmpty()) 30 | { 31 | try 32 | { 33 | m_Logger.log( Level.FINE, "ThreadHelpLauncher Wait - Running & about to try lock: " + this ); 34 | m_Lock.wait(); 35 | m_Logger.log( Level.FINE, "ThreadHelpLauncher Wait - Running & notified : " + this ); 36 | } 37 | catch (InterruptedException e) 38 | { 39 | m_Logger.log(Level.SEVERE, "<"+this.getClass().getName()+">" + "ThreadHelpLauncher Wait - EXCEPTION CAUGHT.", e); 40 | } 41 | } 42 | m_Logger.log( Level.FINE, "ThreadHelpLauncher Wait - No longer running: " + this); 43 | } 44 | } 45 | 46 | public ThreadHelpLauncher() 47 | { 48 | // Start thread immediately on creation 49 | m_HelpLauncherThread = new Thread(this); 50 | m_HelpLauncherThread.start(); 51 | 52 | // Thread synchronization 53 | m_Lock = new Object(); 54 | } 55 | 56 | 57 | public synchronized void addHelpRequest(String resName) 58 | { 59 | this.m_RequestList.add(resName); 60 | } 61 | 62 | public void run() 63 | { 64 | // Endless loop for this thread 65 | while(true) 66 | { 67 | waitUntilFree(); 68 | 69 | synchronized(m_Lock) 70 | { 71 | // Launch the analyze method 72 | if (!m_RequestList.isEmpty()) 73 | { 74 | String file = m_RequestList.get(0); 75 | m_RequestList.remove(0); 76 | 77 | openPdf(file); 78 | 79 | m_Lock.notifyAll(); 80 | } 81 | } 82 | } 83 | } 84 | 85 | public void openPdf(String pdf) 86 | { 87 | if (Desktop.isDesktopSupported()) 88 | { 89 | m_Logger.log(Level.INFO, "Opening the help file. Will take a few seconds ..."); 90 | 91 | // InputStream jarPdf = getClass().getClassLoader().getResourceAsStream(pdf); 92 | InputStream jarPdf = MainNightScoutLoader.class.getResourceAsStream(pdf); 93 | 94 | try 95 | { 96 | File pdfTemp = new File("NightscoutLoader_Temp.pdf"); 97 | // Extraction du PDF qui se situe dans l'archive 98 | FileOutputStream fos = new FileOutputStream(pdfTemp); 99 | while (jarPdf.available() > 0) 100 | { 101 | fos.write(jarPdf.read()); 102 | } // while (pdfInJar.available() > 0) 103 | fos.close(); 104 | // Ouverture du PDF 105 | Desktop.getDesktop().open(pdfTemp); 106 | } // try 107 | 108 | catch (IOException e) 109 | { 110 | m_Logger.log(Level.SEVERE, "<"+this.getClass().getName()+">" + " openPdf Exception caught opening " + pdf, e); 111 | 112 | } // catch (IOException e) 113 | 114 | m_Logger.log(Level.INFO, "Help file opened"); 115 | } 116 | 117 | else 118 | { 119 | m_Logger.log(Level.WARNING, "<"+this.getClass().getName()+">" + " Desktop Not Supported "); 120 | } 121 | 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/loader/DataLoadNightScoutEntries.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | import com.mongodb.BasicDBObject; 3 | import com.mongodb.BasicDBObjectBuilder; 4 | import com.mongodb.DBCollection; 5 | import com.mongodb.DBCursor; 6 | import com.mongodb.DBObject; 7 | import control.MyLogger; 8 | import control.PrefsNightScoutLoader; 9 | import entity.DBResultEntry; 10 | import mongo.NightscoutMongoDB; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Date; 14 | import java.util.logging.Level; 15 | import java.util.logging.Logger; 16 | import java.net.UnknownHostException; 17 | 18 | public class DataLoadNightScoutEntries extends DataLoadNightScout 19 | { 20 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 21 | // private static final int m_FailedTestLimit = 2; 22 | 23 | // private static Integer m_FailedTests = 0; 24 | 25 | private ArrayList resultsFromDB; 26 | 27 | public DataLoadNightScoutEntries() 28 | { 29 | super(); 30 | resultsFromDB = new ArrayList(); 31 | } 32 | 33 | static public Date getEntryLoadStartDate() 34 | { 35 | int weeksBack = PrefsNightScoutLoader.getInstance().getM_WeeksBackToLoadEntries(); 36 | Date now = new Date(); 37 | long nowLong = now.getTime(); 38 | long thenLong = nowLong - ((long)weeksBack * 7 * 24 * 3600 * 1000); // Arrghh - need to cast this weeks back else get garbage future date! 39 | Date result = new Date(thenLong); 40 | 41 | return result; 42 | } 43 | 44 | public void loadDBResults() throws UnknownHostException 45 | { 46 | /* 47 | * int weeksBack = PrefsNightScoutLoader.getInstance().getM_WeeksBackToLoadEntries(); 48 | Date now = new Date(); 49 | long nowLong = now.getTime(); 50 | long thenLong = nowLong - ((long)weeksBack * 7 * 24 * 3600 * 1000); // Arrghh - need to cast this weeks back else get garbage future date! 51 | Date startDate = new Date(thenLong); 52 | 53 | // final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S"); 54 | // String nowString = new String(df.format(now)); 55 | // String startDatetring = new String(df.format(startDate)); 56 | 57 | loadDBResults(startDate); 58 | */ 59 | 60 | loadDBResults(getEntryLoadStartDate()); 61 | } 62 | 63 | public void loadDBResults(Date startDate) throws UnknownHostException 64 | { 65 | testMongo(); 66 | 67 | if (m_ServerState == MongoDBServerStateEnum.accessible) 68 | { 69 | String timeFld = new String("date"); 70 | 71 | NightscoutMongoDB nsMongoDB = new NightscoutMongoDB(); 72 | DBCollection coll = nsMongoDB.getSensorV2xCollection(); 73 | 74 | resultsFromDB = new ArrayList(); 75 | 76 | BasicDBObject query = new BasicDBObject(); 77 | // Load *all* results 78 | query.put(timeFld, BasicDBObjectBuilder.start("$gte", startDate.getTime()).get()); 79 | 80 | m_Logger.log(Level.FINE, "loadDBResults Mongo Query is now " + query.toString()); 81 | 82 | DBCursor cursor = coll.find(query); 83 | // Sort by time 84 | cursor.sort(new BasicDBObject(timeFld, 1)); 85 | 86 | for (DBObject rs: cursor) 87 | { 88 | // Now create Result objects for each document and store into array 89 | //ResultFromDB res = new ResultFromDB(rs); 90 | 91 | // Switch to new object type 92 | DBResultEntry res = new DBResultEntry(rs); 93 | 94 | resultsFromDB.add(res); 95 | 96 | m_Logger.log(Level.FINEST, "Result added for Nightscout Sensor Result " + rs.toString()); 97 | } 98 | 99 | nsMongoDB.close(); 100 | } 101 | 102 | } 103 | 104 | public ArrayList getResultsFromDB() 105 | { 106 | return resultsFromDB; 107 | } 108 | 109 | 110 | @Override 111 | protected String getDevice() 112 | { 113 | return new String(""); // Not used 114 | } 115 | 116 | @Override 117 | protected String getRequestType() 118 | { 119 | return new String ("Data Load Entries "); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/loader/DataLoadRocheCSV.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | import control.MyLogger; 11 | import entity.DBResult; 12 | import entity.DBResultRoche; 13 | 14 | public class DataLoadRocheCSV extends DataLoadCSVFile 15 | { 16 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 17 | private static final String m_RocheSplitBy = "\t"; 18 | 19 | @Override 20 | protected DBResult makeDBResult(String[] res) 21 | { 22 | DBResultRoche result = new DBResultRoche(res); 23 | return result; 24 | } 25 | 26 | @Override 27 | protected String loadStringName() 28 | { 29 | return "Roche"; 30 | } 31 | 32 | @Override 33 | protected String getSplitBy() 34 | { 35 | return m_RocheSplitBy; 36 | } 37 | 38 | public static boolean isRoche(String fileName) 39 | { 40 | boolean result = false; 41 | BufferedReader br = null; 42 | String line = ""; 43 | String cvsSplitBy = m_RocheSplitBy; 44 | 45 | // Expected Format 46 | boolean ln1Year = false; 47 | boolean ln1Month = false; 48 | boolean ln1Day = false; 49 | boolean ln1DayName = false; 50 | boolean ln1Time = false; // 640 51 | boolean ln1TimeSlot = false; // Veo 52 | boolean ln1Result = false; // Veo 53 | boolean ln1ResultType = false; // Veo 54 | boolean ln1MealType = false; // Veo 55 | boolean ln1Duration = false; // Veo 56 | 57 | int ln = 0; 58 | int maxLines = 1; // Just one line 59 | 60 | try 61 | { 62 | br = new BufferedReader(new FileReader(fileName)); 63 | while ((ln <= maxLines) && (line = br.readLine()) != null) 64 | { 65 | ln++; 66 | // use comma as separator 67 | String[] rs = line.split(cvsSplitBy); 68 | 69 | if (ln == 1) 70 | { 71 | int i = 0; 72 | ln1Year = (rs.length > i && rs[i++].equals("Year")) ? true : false; 73 | ln1Month = (rs.length > i && rs[i++].equals("Month")) ? true : false; 74 | ln1Day = (rs.length > i && rs[i++].equals("Day")) ? true : false; 75 | ln1DayName = (rs.length > i && rs[i++].equals("DayName")) ? true : false; 76 | ln1Time = (rs.length > i && rs[i++].equals("Time")) ? true : false; 77 | ln1TimeSlot = (rs.length > i && rs[i++].equals("TimeSlot")) ? true : false; 78 | ln1Result = (rs.length > i && rs[i++].equals("Result")) ? true : false; 79 | ln1ResultType = (rs.length > i && rs[i++].equals("ResultType")) ? true : false; 80 | ln1MealType = (rs.length > i && rs[i++].equals("MealType")) ? true : false; 81 | ln1Duration = (rs.length > i && rs[i++].equals("Duration")) ? true : false; 82 | 83 | } 84 | 85 | } 86 | 87 | result = (ln1Year == true && ln1Month == true && ln1Day == true && 88 | ln1DayName == true && ln1Time == true && ln1TimeSlot == true && 89 | ln1Result == true && ln1ResultType == true && ln1MealType == true && ln1Duration == true) ? true : false; 90 | 91 | } 92 | catch (FileNotFoundException e) 93 | { 94 | m_Logger.log(Level.SEVERE, "" + "isRoche: FileNotFoundException. File " + fileName + " Error " + e.getMessage()); 95 | 96 | e.printStackTrace(); 97 | } 98 | catch (IOException e) 99 | { 100 | m_Logger.log(Level.SEVERE, "" + "isRoche: IOException. File " + fileName + " Error " + e.getMessage()); 101 | e.printStackTrace(); 102 | } 103 | finally 104 | { 105 | if (br != null) 106 | { 107 | try 108 | { 109 | br.close(); 110 | } 111 | catch (IOException e) 112 | { 113 | m_Logger.log(Level.SEVERE, "" + "isMedtronic: IOException closing file. File " + fileName + " Error " + e.getMessage()); 114 | e.printStackTrace(); 115 | } 116 | } 117 | } 118 | 119 | return result; 120 | } 121 | 122 | 123 | } 124 | 125 | -------------------------------------------------------------------------------- /src/test/java/control/TestMongoConnection.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.io.IOException; 4 | 5 | import org.junit.jupiter.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import com.mongodb.MongoClient; 9 | import com.mongodb.MongoClientURI; 10 | import com.mongodb.MongoSocketWriteException; 11 | import com.mongodb.MongoTimeoutException; 12 | import com.mongodb.client.MongoDatabase; 13 | import com.mongodb.client.MongoIterable; 14 | 15 | public class TestMongoConnection { 16 | 17 | private static String m_ValidMongoURIString = null; 18 | private static String m_ValidMongoDBString = null; 19 | private static String m_InValidMongoURIString = null; 20 | private static String m_InValidMongoDBString = null; 21 | 22 | 23 | public TestMongoConnection() 24 | { 25 | setup(); 26 | } 27 | 28 | @Test 29 | public void test1() 30 | { 31 | // Support some level of Mongo connection testing without need to hard code sensitive 32 | // connection strings 33 | // 34 | // Instead, these get passed in through the mvn command as follows: 35 | // 36 | // 37 | // mvn -DVALID_MONGO_URI="mongodb+srv://valid_user:pass@heroku.mongo.net/db?retryWrites=true&w=majority" ^ 38 | // -DVALID_MONGO_DB="db" ^ 39 | // -DINVALID_MONGO_URI="mongodb+srv://invalid_user:pass@heroku.mongo.net/db?retryWrites=true&w=majority" ^ 40 | // -DINVALID_MONGO_DB="db" 41 | 42 | m_ValidMongoURIString = System.getProperty("VALID_MONGO_URI"); 43 | m_ValidMongoDBString = System.getProperty("VALID_MONGO_DB"); 44 | m_InValidMongoURIString = System.getProperty("INVALID_MONGO_URI"); 45 | m_InValidMongoDBString = System.getProperty("INVALID_MONGO_DB"); 46 | 47 | testConnection(m_ValidMongoURIString, m_ValidMongoDBString, true); 48 | testConnection(m_InValidMongoURIString, m_InValidMongoDBString, false); 49 | 50 | // testConnection(uri3, db3); 51 | // testConnection(uri4, db4); 52 | } 53 | 54 | private void testConnection(String uri, String dbString, Boolean expectSucceed) 55 | { 56 | if (uri != null && uri.length() > 0 && dbString != null && dbString.length() > 0) 57 | { 58 | MongoClientURI dbURI = new MongoClientURI(uri); 59 | MongoClient mongo = new MongoClient(dbURI); 60 | 61 | Boolean connectionSuccessBoolean = true; 62 | 63 | try { 64 | MongoDatabase database = mongo.getDatabase(dbString); 65 | 66 | MongoIterable list = database.listCollectionNames(); 67 | for (String name : list) { 68 | System.out.println(uri + " has " + name); 69 | } 70 | } 71 | catch (MongoSocketWriteException e) 72 | { 73 | connectionSuccessBoolean = false; 74 | } 75 | catch (MongoTimeoutException e) 76 | { 77 | connectionSuccessBoolean = false; 78 | } 79 | catch (Exception e) 80 | { 81 | connectionSuccessBoolean = false; 82 | } 83 | 84 | Assertions.assertTrue(expectSucceed == connectionSuccessBoolean, 85 | "Attempted connection to " + uri + ":" + dbString + ". Expected " 86 | + (expectSucceed == true ? "successful connection " : "failed connection") 87 | + " but got " 88 | + (connectionSuccessBoolean == true ? "successful connection " : "failed connection") 89 | ); 90 | 91 | mongo.close(); 92 | } 93 | else 94 | { 95 | System.out.println("**** Mongo Connection tests skipped. ****" 96 | + " (Test for connection success " + expectSucceed + ") " 97 | + "Use mvn parameters to set valid and invalid URIs for testing: " 98 | + " -DVALID_MONGO_URI & -DVALID_MONGO_DB, and -DINVALID_MONGO_URI & -DINVALID_MONGO_DB" 99 | ); 100 | } 101 | } 102 | 103 | private void setup() 104 | { 105 | try { 106 | 107 | // Set log level to 10 (warning). Other new option is 20 (severe) 108 | // This quietens down the output significantly 109 | PrefsNightScoutLoader.getInstance().setM_LogLevel(10); 110 | 111 | MyLogger.setup(true); 112 | } catch (IOException e) { 113 | // TODO Auto-generated catch block 114 | e.printStackTrace(); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/control/ThreadAutotune.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | 6 | import miscellaneous.RemoteLinuxServer; 7 | 8 | abstract 9 | public class ThreadAutotune implements Runnable 10 | { 11 | protected static final Logger m_Logger = Logger.getLogger( MyLogger.class.getName() ); 12 | 13 | // Separate thread for RemoteLinuxServer 14 | protected Thread m_AututuneThread; 15 | 16 | // Data Loader used by thread 17 | protected RemoteLinuxServer m_Autotuner; 18 | 19 | protected Boolean m_LoadRunning; 20 | // static Object m_Lock = new Object(); 21 | protected Object m_Lock; 22 | 23 | // Sub classes must override this 24 | abstract protected void doAutotuneTask(); 25 | 26 | // Thread Synchronization 27 | public void waitUntilFree() 28 | { 29 | synchronized(m_Lock) 30 | { 31 | while (m_LoadRunning) 32 | { 33 | try 34 | { 35 | m_Logger.log( Level.FINE, "ThreadDataLoad Wait - Running & about to try lock: " + this ); 36 | m_Lock.wait(); 37 | m_Logger.log( Level.FINE, "ThreadDataLoad Wait - Running & notified : " + this ); 38 | } 39 | catch (InterruptedException e) 40 | { 41 | m_Logger.log(Level.SEVERE, "<"+this.getClass().getName()+">" + "ThreadDataLoad Wait - EXCEPTION CAUGHT.", e); 42 | } 43 | } 44 | m_Logger.log( Level.FINE, "ThreadDataLoad Wait - No longer running: " + this); 45 | } 46 | } 47 | // Handler to notify when load completes 48 | AutotuneCompleteHandler m_CompleteHandler; 49 | 50 | // Thread Handler for resynchronization 51 | public static abstract class AutotuneCompleteHandler 52 | { 53 | private Object m_Object; 54 | public AutotuneCompleteHandler(Object obj) 55 | { 56 | m_Object = obj; 57 | } 58 | public abstract void runAutotuneComplete(Object obj, String message); 59 | public abstract void exceptionRaised(String message); 60 | 61 | public Object getM_Object() 62 | { 63 | return m_Object; 64 | } 65 | } 66 | 67 | public ThreadAutotune(RemoteLinuxServer autoTuner) 68 | { 69 | m_LoadRunning = true; // Initialise the thread in running state 70 | m_AututuneThread = new Thread(this); 71 | m_Autotuner = autoTuner; 72 | m_CompleteHandler = null; 73 | 74 | // Thread synchronization 75 | m_Lock = new Object(); 76 | } 77 | 78 | public void runThreadCommand(AutotuneCompleteHandler completeHandler) 79 | { 80 | m_CompleteHandler = completeHandler; 81 | m_AututuneThread.start(); 82 | } 83 | 84 | public void run() 85 | { 86 | m_LoadRunning = true; 87 | synchronized(m_Lock) 88 | { 89 | // Launch the data load read method 90 | try 91 | { 92 | doAutotuneTask(); 93 | } 94 | 95 | catch (Exception e) 96 | { 97 | m_CompleteHandler.exceptionRaised("Thread Exception: " + e.getLocalizedMessage()); 98 | } 99 | finally 100 | { 101 | m_CompleteHandler.runAutotuneComplete(m_CompleteHandler.getM_Object(), ""); 102 | } 103 | m_LoadRunning = false; 104 | m_Lock.notifyAll(); 105 | 106 | // Kill the thread 107 | m_AututuneThread.interrupt(); 108 | } 109 | } 110 | 111 | /** 112 | * @return the m_AututuneThread 113 | */ 114 | public synchronized Thread getM_AututuneThread() { 115 | return m_AututuneThread; 116 | } 117 | 118 | /** 119 | * @param m_AututuneThread the m_AututuneThread to set 120 | */ 121 | public synchronized void setM_AututuneThread(Thread m_AututuneThread) { 122 | this.m_AututuneThread = m_AututuneThread; 123 | } 124 | 125 | /** 126 | * @return the m_LoadRunning 127 | */ 128 | public Boolean getM_LoadRunning() { 129 | return m_LoadRunning; 130 | } 131 | 132 | /** 133 | * @param m_LoadRunning the m_LoadRunning to set 134 | */ 135 | public void setM_LoadRunning(Boolean m_LoadRunning) { 136 | this.m_LoadRunning = m_LoadRunning; 137 | } 138 | 139 | /** 140 | * @return the m_Autotuner 141 | */ 142 | public synchronized RemoteLinuxServer getM_Autotuner() { 143 | return m_Autotuner; 144 | } 145 | 146 | /** 147 | * @param m_Autotuner the m_Autotuner to set 148 | */ 149 | public synchronized void setM_Autotuner(RemoteLinuxServer m_Autotuner) { 150 | this.m_Autotuner = m_Autotuner; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/analysis/AnalyzerTabs.java: -------------------------------------------------------------------------------- 1 | package analysis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | 7 | import control.MyLogger; 8 | import control.PrefsNightScoutLoader; 9 | 10 | public class AnalyzerTabs 11 | { 12 | // Implements the Singleton Design Pattern 13 | private static AnalyzerTabs m_Instance=null; 14 | 15 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 16 | 17 | public static AnalyzerTabs getInstance() 18 | { 19 | if (m_Instance == null) 20 | { 21 | m_Instance = new AnalyzerTabs(); 22 | } 23 | return m_Instance; 24 | } 25 | 26 | class Tab 27 | { 28 | private String m_TabName; 29 | private boolean m_Enabled; 30 | 31 | Tab(String tabName, boolean enabled) 32 | { 33 | m_TabName = new String(tabName); 34 | m_Enabled = enabled; 35 | } 36 | 37 | /** 38 | * @return the m_TabName 39 | */ 40 | public synchronized String getM_TabName() { 41 | return m_TabName; 42 | } 43 | 44 | /** 45 | * @param m_TabName the m_TabName to set 46 | */ 47 | public synchronized void setM_TabName(String m_TabName) { 48 | this.m_TabName = m_TabName; 49 | } 50 | 51 | /** 52 | * @return the m_Enabled 53 | */ 54 | public synchronized boolean isM_Enabled() { 55 | return m_Enabled; 56 | } 57 | 58 | /** 59 | * @param m_Enabled the m_Enabled to set 60 | */ 61 | public synchronized void setM_Enabled(boolean m_Enabled) { 62 | this.m_Enabled = m_Enabled; 63 | } 64 | } 65 | 66 | private ArrayList m_ListOfTabs; 67 | private ArrayList m_MinimalListOfTabs; 68 | 69 | 70 | private AnalyzerTabs() 71 | { 72 | m_ListOfTabs = new ArrayList(); 73 | m_MinimalListOfTabs = new ArrayList(); 74 | } 75 | 76 | boolean isTabEnabled(String tabName) 77 | { 78 | boolean advancedSettings = PrefsNightScoutLoader.getInstance().isM_AdvancedSettings(); 79 | 80 | // Only if advanced is true do we use the set values. 81 | // Else ignore and use the minimal list instead. 82 | ArrayList searchList = advancedSettings == true ? m_ListOfTabs : m_MinimalListOfTabs; 83 | 84 | boolean result = false; 85 | for (Tab t : searchList) 86 | { 87 | // if (t.getM_TabName().equals(tabName)) 88 | if (tabName.equals(t.getM_TabName())) 89 | { 90 | result = t.isM_Enabled(); 91 | break; 92 | } 93 | } 94 | return result; 95 | } 96 | 97 | public void setupListOfTabs() 98 | { 99 | int excelOutputLevel = PrefsNightScoutLoader.getInstance().getM_AnalyzerExcelOutputLevel(); 100 | setupListOfTabs(this.m_ListOfTabs, excelOutputLevel); 101 | setupListOfTabs(this.m_MinimalListOfTabs, 0); 102 | 103 | m_Logger.log(Level.FINE, "Added full list"); 104 | } 105 | 106 | 107 | private void setupListOfTabs(ArrayList searchList, int level) 108 | { 109 | searchList.clear(); 110 | 111 | // level = 0 ==> Minimal 112 | // level = 1 ==> Moderate 113 | // level = 2 ==> Maximum 114 | 115 | if (level >= 0) searchList.add(new Tab("Guide to Tabs", true)); 116 | if (level >= 0) searchList.add(new Tab("Autotune", true)); 117 | if (level >= 0) searchList.add(new Tab("Recurring Trends", true)); 118 | if (level == 2) searchList.add(new Tab("Trends", true)); 119 | if (level >= 1) searchList.add(new Tab("Skipped Meal Trends", true)); 120 | if (level >= 0) searchList.add(new Tab("CGM Summary", true)); 121 | if (level >= 0) searchList.add(new Tab("CGM Heat Map", true)); 122 | if (level >= 1) searchList.add(new Tab("BGs Outside Range", true)); 123 | if (level >= 1) searchList.add(new Tab("Day Summaries", true)); 124 | if (level == 2) searchList.add(new Tab("Single Results", true)); 125 | if (level == 2) searchList.add(new Tab("Treatment Data Analyzed", true)); 126 | if (level == 2) searchList.add(new Tab("In Range CGM Trend Result Entries", true)); 127 | if (level == 2) searchList.add(new Tab("In Range CGM Entry Intervals", true)); 128 | if (level == 2) searchList.add(new Tab("In Range CGM Results", true)); 129 | if (level == 2) searchList.add(new Tab("Full History Trends", true)); 130 | if (level >= 1) searchList.add(new Tab("Comparison to Full History", true)); 131 | if (level >= 0) searchList.add(new Tab("Parameters", true)); 132 | if (level >= 0) searchList.add(new Tab("Settings", true)); 133 | if (level >= 0) searchList.add(new Tab("Trend Explanations", true)); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/miscellaneous/FileChecker.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | 3 | import loader.DataLoadCellNovo; 4 | import loader.DataLoadDiasend; 5 | import loader.DataLoadLibreView; 6 | import loader.DataLoadMedtronic; 7 | import loader.DataLoadOmniPod; 8 | import loader.DataLoadRocheCSV; 9 | import loader.DataLoadTandem; 10 | 11 | public class FileChecker 12 | { 13 | 14 | // Opens supplied file and checks validity against known types... 15 | public enum FileCheckType 16 | { 17 | INVALID, 18 | 19 | Medtronic, 20 | Diasend, 21 | LibreView, 22 | OmniPod, 23 | RocheSQLExtract, 24 | Tandem, 25 | CellNovo 26 | } 27 | 28 | public static String getFileTypeStr(FileCheckType fct) 29 | { 30 | String result = new String(""); 31 | 32 | switch (fct) 33 | { 34 | case INVALID : result = "INVALID"; break; 35 | case Medtronic : result = "Medtronic"; break; 36 | case Diasend : result = "Diasend"; break; 37 | case LibreView : result = "LibreView"; break; 38 | case OmniPod : result = "OmniPod"; break; 39 | case RocheSQLExtract : result = "Roche SQL Extract"; break; 40 | case Tandem : result = "Tandem"; break; 41 | case CellNovo : result = "CellNovo"; break; 42 | 43 | default : result = "UNKNOWN"; break; 44 | } 45 | 46 | return result; 47 | } 48 | 49 | public static FileCheckType checkFile(String filename) 50 | { 51 | FileCheckType result = FileChecker.FileCheckType.INVALID; 52 | 53 | // Protect these checks by file name type 54 | if (filename.contains(".xls")) 55 | { 56 | if (isDiasend(filename)) 57 | { 58 | result = FileChecker.FileCheckType.Diasend; 59 | } 60 | } 61 | else if (filename.contains(".csv")) 62 | { 63 | if (isLibreView(filename)) 64 | { 65 | result = FileChecker.FileCheckType.LibreView; 66 | } 67 | else if (isMedtronic(filename)) 68 | { 69 | result = FileChecker.FileCheckType.Medtronic; 70 | } 71 | else if (isRocheCSV(filename)) 72 | { 73 | result = FileChecker.FileCheckType.RocheSQLExtract; 74 | } 75 | else if (isTandem(filename)) 76 | { 77 | result = FileChecker.FileCheckType.Tandem; 78 | } 79 | else if (isCellNovo(filename)) 80 | { 81 | result = FileChecker.FileCheckType.CellNovo; 82 | } 83 | } 84 | else if (filename.contains(".ibf") && isOmniPod(filename)) 85 | { 86 | result = FileChecker.FileCheckType.OmniPod; 87 | } 88 | 89 | return result; 90 | } 91 | 92 | public static FileCheckType checkBinaryFile(String filename) 93 | { 94 | FileCheckType result = FileChecker.FileCheckType.INVALID; 95 | 96 | if (isLibreView(filename)) 97 | { 98 | result = FileChecker.FileCheckType.LibreView; 99 | } 100 | else if (isMedtronic(filename)) 101 | { 102 | result = FileChecker.FileCheckType.Medtronic; 103 | } 104 | else if (isDiasend(filename)) 105 | { 106 | result = FileChecker.FileCheckType.Diasend; 107 | } 108 | else if (isRocheCSV(filename)) 109 | { 110 | result = FileChecker.FileCheckType.RocheSQLExtract; 111 | } 112 | else if (isTandem(filename)) 113 | { 114 | result = FileChecker.FileCheckType.Tandem; 115 | } 116 | else if (isCellNovo(filename)) 117 | { 118 | result = FileChecker.FileCheckType.CellNovo; 119 | } 120 | 121 | return result; 122 | } 123 | 124 | 125 | private static boolean isLibreView(String fileName) 126 | { 127 | boolean result = DataLoadLibreView.isLibreView(fileName); 128 | return result; 129 | } 130 | 131 | private static boolean isMedtronic(String fileName) 132 | { 133 | boolean result = DataLoadMedtronic.isMedtronic(fileName); 134 | return result; 135 | } 136 | 137 | private static boolean isDiasend(String fileName) 138 | { 139 | boolean result = DataLoadDiasend.isDiasend(fileName); 140 | return result; 141 | } 142 | private static boolean isOmniPod(String fileName) 143 | { 144 | boolean result = DataLoadOmniPod.isOmniPod(fileName); 145 | return result; 146 | } 147 | 148 | private static boolean isRocheCSV(String fileName) 149 | { 150 | boolean result = DataLoadRocheCSV.isRoche(fileName); 151 | return result; 152 | } 153 | 154 | private static boolean isTandem(String fileName) 155 | { 156 | boolean result = DataLoadTandem.isTandem(fileName); 157 | return result; 158 | } 159 | 160 | private static boolean isCellNovo(String fileName) 161 | { 162 | boolean result = DataLoadCellNovo.isCellNovo(fileName); 163 | return result; 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /bin/NightScoutLoader.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | REM --------------------------------------------------------------------------- 3 | REM 4 | REM Run script for launching the NightScoutLoader application 5 | REM 6 | REM 1 Checks that jar file is correctly installed in folder 7 | REM 2 Checks that the C:\Temp folder exists for log file 8 | REM 3 Ensures that correct parameters are passed to runtime JVM 9 | REM 10 | REM --------------------------------------------------------------------------- 11 | SETLOCAL enabledelayedexpansion 12 | 13 | REM 14 | REM Set some variables up 15 | REM 16 | SET jarfile=NightScoutLoader.jar 17 | SET tmpdir=C:\Temp 18 | SET msgdir=%temp% 19 | 20 | REM 21 | REM Ensure that the script runs from the same directory the script resides in 22 | REM The assumption is that both the BAT script and the JAR file are in the same 23 | REM directory. 24 | REM 25 | cd /D "%~dp0" 26 | 27 | REM --------------------------------------------------------------------------- 28 | REM 29 | REM Do some basic checks and alert if needed 30 | REM 31 | REM --------------------------------------------------------------------------- 32 | 33 | REM 34 | REM Java file needs to be present 35 | REM 36 | if NOT EXIST %jarfile% ( 37 | CALL :displayMessage CRITICAL "NightScoutLoader Jar file needs to be present as '%jarfile%'" "" "Did the download append '(1)' to the filename perhaps?" "" "If so, please rename the Jar file to '%jarfile%' in directory %~dp0" 38 | SET ERRORLEVEL=1 39 | EXIT /B %ERRORLEVEL% 40 | ) 41 | 42 | REM 43 | REM NightScoutLoader logs to %tmpdir% so ensure it exists too 44 | REM 45 | if NOT EXIST %tmpdir% ( 46 | md %tmpdir% 47 | if NOT EXIST %tmpdir% ( 48 | CALL :displayMessage EXCLAMATION "NightScoutLoader relies on %tmpdir% by default for its log file" "" "However, you don't have permission to create this folder" "" "Use elevated permissions to create manually" 49 | SET ERRORLEVEL=1 50 | EXIT /B %ERRORLEVEL% 51 | ) 52 | CALL :displayMessage INFORMATION "Successfully created %tmpdir% for NightScoutLoader log file" "" "Select OK to continue" 53 | ) 54 | 55 | REM 56 | REM Invoke NightScoutLoader with options to increase memory and also with the TLS option set 57 | REM TLS is needed to successfully connect to Mongo Atlas on Windows 58 | REM 59 | java -Xmx1024m -Xms128m -Djdk.tls.client.protocols=TLSv1.2 -jar %jarfile% 60 | EXIT /B %ERRORLEVEL% 61 | 62 | REM --------------------------------------------------------------------------- 63 | REM 64 | REM Display Message function for notifications 65 | REM 66 | REM %~1 CRITICAL, QUESTION, EXCLAMATION or INFORMATION - sets msgbox symbol 67 | REM %~2 First line message 68 | REM %~2 Second line message 69 | REM ... 70 | REM %~2 Fifth line message 71 | REM --------------------------------------------------------------------------- 72 | :displayMessage 73 | SET symbol="" 74 | SET header="" 75 | 76 | if "%~1"=="CRITICAL" ( 77 | SET symbol=, vbCritical + vbOKOnly 78 | SET header="SETUP ERROR:" 79 | ) 80 | if "%~1"=="QUESTION" ( 81 | SET symbol=, vbQuestion + vbOKOnly 82 | SET header="" 83 | ) 84 | if "%~1"=="EXCLAMATION" ( 85 | SET symbol=, vbExclamation + vbOKOnly 86 | SET header="SETUP ERROR:" 87 | ) 88 | if "%~1"=="INFORMATION" ( 89 | SET symbol=, vbInformation + vbOKOnly 90 | SET header="Please Note:" 91 | ) 92 | shift 93 | 94 | IF NOT "%~5"=="" goto fiveLines 95 | IF NOT "%~4"=="" goto fourLines 96 | IF NOT "%~3"=="" goto threeLines 97 | IF NOT "%~2"=="" goto twoLines 98 | IF NOT "%~1"=="" goto oneLine 99 | 100 | :oneLine 101 | echo MSGBOX %header% ^& vbCrLf ^& vbCrLf ^& "%~1" %symbol% > %msgdir%\TEMPmessage.vbs 102 | goto runVB 103 | :twoLines 104 | echo MSGBOX %header% ^& vbCrLf ^& vbCrLf ^& "%~1" ^& vbCrLf ^& "%~2" %symbol% > %msgdir%\TEMPmessage.vbs 105 | goto runVB 106 | :threeLines 107 | echo MSGBOX %header% ^& vbCrLf ^& vbCrLf ^& "%~1" ^& vbCrLf ^& "%~2" ^& vbCrLf ^& "%~3" %symbol% > %msgdir%\TEMPmessage.vbs 108 | goto runVB 109 | :fourLines 110 | echo MSGBOX %header% ^& vbCrLf ^& vbCrLf ^& "%~1" ^& vbCrLf ^& "%~2" ^& vbCrLf ^& "%~3" ^& vbCrLf ^& "%~4" %symbol% > %msgdir%\TEMPmessage.vbs 111 | goto runVB 112 | :fiveLines 113 | echo MSGBOX %header% ^& vbCrLf ^& vbCrLf ^& "%~1" ^& vbCrLf ^& "%~2" ^& vbCrLf ^& "%~3" ^& vbCrLf ^& "%~4" ^& vbCrLf ^& "%~5" %symbol% > %msgdir%\TEMPmessage.vbs 114 | goto runVB 115 | 116 | :runVB 117 | call %msgdir%\TEMPmessage.vbs 118 | del %msgdir%\TEMPmessage.vbs /f /q 119 | EXIT /B 0 -------------------------------------------------------------------------------- /src/main/java/miscellaneous/BinaryStruct.java: -------------------------------------------------------------------------------- 1 | package miscellaneous; 2 | //package org.DavidRichardson.NightscoutLoaderMaven; 3 | // 4 | //import java.util.ArrayList; 5 | //import java.util.regex.Matcher; 6 | //import java.util.regex.Pattern; 7 | // 8 | //public class BinaryStruct 9 | //{ 10 | // 11 | // enum VarType 12 | // { 13 | // vt_Unknown, 14 | // 15 | // vt_short, 16 | // vt_signed_short, 17 | // vt_int, 18 | // vt_signed_int, 19 | // vt_byte, 20 | // vt_signed_byte, 21 | // vt_float, 22 | // vt_BE_short, 23 | // vt_BE_signed_short, 24 | // vt_BE_float, 25 | // vt_BE_int, 26 | // vt_BE_signed_int, 27 | // vt_ZString, 28 | // vt_String, 29 | // }; 30 | // 31 | // private static FieldType[] m_FieldType = new FieldType[15]; 32 | // private static boolean m_Initialized = false; 33 | // 34 | // private int m_Count = 0; 35 | // private String m_Expression = ""; 36 | // 37 | // private class FieldType 38 | // { 39 | // private char m_fieldType; 40 | // private int m_length; 41 | // private VarType m_VarType; 42 | // 43 | // FieldType(char f, int l, VarType v) 44 | // { 45 | // m_fieldType = f; 46 | // m_length = l; 47 | // m_VarType = v; 48 | // } 49 | // 50 | // /** 51 | // * @return the m_fieldType 52 | // */ 53 | // public synchronized char getM_fieldType() { 54 | // return m_fieldType; 55 | // } 56 | // 57 | // /** 58 | // * @param m_fieldType the m_fieldType to set 59 | // */ 60 | // public synchronized void setM_fieldType(char m_fieldType) { 61 | // this.m_fieldType = m_fieldType; 62 | // } 63 | // 64 | // /** 65 | // * @return the m_length 66 | // */ 67 | // public synchronized int getM_length() { 68 | // return m_length; 69 | // } 70 | // 71 | // /** 72 | // * @param m_length the m_length to set 73 | // */ 74 | // public synchronized void setM_length(int m_length) { 75 | // this.m_length = m_length; 76 | // } 77 | // 78 | // /** 79 | // * @return the m_VarType 80 | // */ 81 | // public synchronized VarType getM_VarType() { 82 | // return m_VarType; 83 | // } 84 | // 85 | // /** 86 | // * @param m_VarType the m_VarType to set 87 | // */ 88 | // public synchronized void setM_VarType(VarType m_VarType) { 89 | // this.m_VarType = m_VarType; 90 | // } 91 | // } 92 | // 93 | // // See parseformat in struct.js from tidepool on which this is modeled 94 | // public static ArrayList parseFormat(String format) 95 | // { 96 | // ArrayList result = new ArrayList(); 97 | // 98 | // int count = 0; 99 | // String exp = new String(""); 100 | // 101 | // Pattern formatPattern = Pattern.compile("(([0-9]*)([a-zA-Z.]))+"); 102 | // Matcher formatMatcher = formatPattern.matcher(format); 103 | // 104 | // while (formatMatcher.find()) 105 | // { 106 | // count = Integer.parseInt(formatMatcher.group(1)); 107 | // exp = formatMatcher.group(2); 108 | // BinaryStruct entry = new BinaryStruct(count, exp); 109 | // result.add(entry); 110 | // } 111 | // 112 | // return result; 113 | // } 114 | // 115 | // public BinaryStruct(int count, String exp) 116 | // { 117 | // initialize(); 118 | // m_Count = count; 119 | // m_Expression = new String(exp); 120 | // } 121 | // 122 | // public BinaryStruct() 123 | // { 124 | // initialize(); 125 | // } 126 | // 127 | // private void initialize() 128 | // { 129 | // if (m_Initialized == false) 130 | // { 131 | // m_Initialized = true; 132 | // 133 | // int i = 0; 134 | // 135 | // m_FieldType[i++] = new FieldType('i', 4, VarType.vt_int); 136 | // m_FieldType[i++] = new FieldType('n', 4, VarType.vt_signed_int); 137 | // m_FieldType[i++] = new FieldType('s', 2, VarType.vt_short); 138 | // m_FieldType[i++] = new FieldType('h', 2, VarType.vt_signed_short); 139 | // m_FieldType[i++] = new FieldType('b', 1, VarType.vt_byte); 140 | // m_FieldType[i++] = new FieldType('y', 1, VarType.vt_signed_byte); 141 | // m_FieldType[i++] = new FieldType('B', 0, VarType.vt_String); // was bytes ... 142 | // m_FieldType[i++] = new FieldType('f', 4, VarType.vt_float); 143 | // m_FieldType[i++] = new FieldType('F', 4, VarType.vt_BE_float); 144 | // m_FieldType[i++] = new FieldType('I', 4, VarType.vt_BE_int); 145 | // m_FieldType[i++] = new FieldType('N', 4, VarType.vt_BE_signed_int); 146 | // m_FieldType[i++] = new FieldType('S', 2, VarType.vt_BE_short); 147 | // m_FieldType[i++] = new FieldType('H', 2, VarType.vt_BE_signed_short); 148 | // m_FieldType[i++] = new FieldType('z', 0, VarType.vt_ZString); 149 | // m_FieldType[i++] = new FieldType('Z', 0, VarType.vt_String); 150 | // 151 | // } 152 | // } 153 | //} 154 | // 155 | // 156 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultPumpSettingBasal.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import org.apache.poi.hssf.usermodel.HSSFRow; 4 | 5 | public class DBResultPumpSettingBasal extends DBResultPumpSetting 6 | { 7 | private String m_BasalProfileName; 8 | 9 | public DBResultPumpSettingBasal(String basalProfileName, HSSFRow row) 10 | { 11 | super(row); 12 | m_BasalProfileName = new String(basalProfileName); 13 | } 14 | 15 | public String toString() 16 | { 17 | return String.format("Profile Name: %s, Index: %d, Time: %s, Value: %g", 18 | m_BasalProfileName, getM_Index(), getM_Time(), getM_BasalValue()); 19 | } 20 | 21 | 22 | /** 23 | * @return the m_BasalProfileName 24 | */ 25 | public synchronized String getM_BasalProfileName() { 26 | return m_BasalProfileName; 27 | } 28 | 29 | /** 30 | * @param m_BasalProfileName the m_BasalProfileName to set 31 | */ 32 | public synchronized void setM_BasalProfileName(String m_BasalProfileName) { 33 | this.m_BasalProfileName = m_BasalProfileName; 34 | } 35 | 36 | /** 37 | * @return the m_BasalValue 38 | */ 39 | public synchronized Double getM_BasalValue() { 40 | return getM_TimeBoundValue(); 41 | } 42 | 43 | /** 44 | * @param m_BasalValue the m_BasalValue to set 45 | */ 46 | public synchronized void setM_BasalValue(Double m_BasalValue) { 47 | setM_TimeBoundValue(m_BasalValue); 48 | } 49 | } 50 | 51 | 52 | //Original class definition 53 | // 54 | //package davidRichardson; 55 | // 56 | //import org.apache.poi.hssf.usermodel.HSSFCell; 57 | //import org.apache.poi.hssf.usermodel.HSSFRow; 58 | // 59 | //public class DBResultDiasendBasalSetting 60 | //{ 61 | // private String m_BasalProfileName; 62 | // private int m_Index; 63 | // private String m_Time; 64 | // private Double m_BasalValue; 65 | // 66 | // private final int m_SettingsFields = 3; 67 | // 68 | // // Utility Function for getting a cell from row as string even if numeric 69 | // static String getCellAsString(HSSFRow row, int index) 70 | // { 71 | // String result; 72 | // // Check type of this cell first 73 | // if (row.getCell(index).getCellType() == HSSFCell.CELL_TYPE_STRING) 74 | // { 75 | // result = row.getCell(index).getStringCellValue(); 76 | // } 77 | // else 78 | // { 79 | // Double result_num = row.getCell(index).getNumericCellValue(); 80 | // result = result_num.toString(); 81 | // } 82 | // return result; 83 | // } 84 | // 85 | // DBResultDiasendBasalSetting(String basalProfileName, HSSFRow row) 86 | // { 87 | // m_BasalProfileName = new String(basalProfileName); 88 | // 89 | // int maxColumns = row.getPhysicalNumberOfCells(); 90 | // if (maxColumns == m_SettingsFields) 91 | // { 92 | // Double cell1 = row.getCell(0).getNumericCellValue(); 93 | // String cell2 = row.getCell(1).getStringCellValue(); 94 | // Double cell3 = row.getCell(2).getNumericCellValue(); 95 | // 96 | // m_Index = cell1.intValue(); 97 | // m_Time = cell2; 98 | // m_BasalValue = cell3; 99 | // } 100 | // } 101 | // 102 | // public String toString() 103 | // { 104 | // return String.format("Profile Name: %s, Index: %d, Time: %s, Value: %g", 105 | // m_BasalProfileName, m_Index, m_Time, m_BasalValue); 106 | // } 107 | // 108 | // 109 | // /** 110 | // * @return the m_BasalProfileName 111 | // */ 112 | // public synchronized String getM_BasalProfileName() { 113 | // return m_BasalProfileName; 114 | // } 115 | // 116 | // /** 117 | // * @param m_BasalProfileName the m_BasalProfileName to set 118 | // */ 119 | // public synchronized void setM_BasalProfileName(String m_BasalProfileName) { 120 | // this.m_BasalProfileName = m_BasalProfileName; 121 | // } 122 | // 123 | // /** 124 | // * @return the m_Index 125 | // */ 126 | // public synchronized int getM_Index() { 127 | // return m_Index; 128 | // } 129 | // 130 | // /** 131 | // * @param m_Index the m_Index to set 132 | // */ 133 | // public synchronized void setM_Index(int m_Index) { 134 | // this.m_Index = m_Index; 135 | // } 136 | // 137 | // /** 138 | // * @return the m_Time 139 | // */ 140 | // public synchronized String getM_Time() { 141 | // return m_Time; 142 | // } 143 | // 144 | // /** 145 | // * @param m_Time the m_Time to set 146 | // */ 147 | // public synchronized void setM_Time(String m_Time) { 148 | // this.m_Time = m_Time; 149 | // } 150 | // 151 | // /** 152 | // * @return the m_BasalValue 153 | // */ 154 | // public synchronized Double getM_BasalValue() { 155 | // return m_BasalValue; 156 | // } 157 | // 158 | // /** 159 | // * @param m_BasalValue the m_BasalValue to set 160 | // */ 161 | // public synchronized void setM_BasalValue(Double m_BasalValue) { 162 | // this.m_BasalValue = m_BasalValue; 163 | // } 164 | // 165 | // 166 | //} -------------------------------------------------------------------------------- /src/main/java/control/ThreadDataLoad.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.io.IOException; 4 | import java.sql.SQLException; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | 8 | import loader.DataLoadBase; 9 | 10 | 11 | public class ThreadDataLoad implements Runnable 12 | { 13 | private static final Logger m_Logger = Logger.getLogger( MyLogger.class.getName() ); 14 | 15 | // Separate thread for data loads 16 | private Thread m_LoadThread; 17 | 18 | private String m_ThreadNameString; 19 | 20 | /** 21 | * @return the m_LoadThread 22 | */ 23 | public synchronized Thread getM_LoadThread() { 24 | return m_LoadThread; 25 | } 26 | 27 | /** 28 | * @param m_LoadThread the m_LoadThread to set 29 | */ 30 | public synchronized void setM_LoadThread(Thread m_LoadThread) { 31 | this.m_LoadThread = m_LoadThread; 32 | } 33 | 34 | // Data Loader used by thread 35 | private DataLoadBase m_DataLoader; 36 | 37 | private Boolean m_LoadRunning; 38 | // static Object m_Lock = new Object(); 39 | private Object m_Lock; 40 | 41 | // Thread Synchronization 42 | public void waitUntilFree() 43 | { 44 | synchronized(m_Lock) 45 | { 46 | while (m_LoadRunning) 47 | { 48 | try 49 | { 50 | m_Logger.log( Level.FINE, "ThreadDataLoad Wait - Running & about to try lock: " + this ); 51 | m_Lock.wait(); 52 | m_Logger.log( Level.FINE, "ThreadDataLoad Wait - Running & notified : " + this ); 53 | } 54 | catch (InterruptedException e) 55 | { 56 | m_Logger.log(Level.SEVERE, "<"+this.getClass().getName()+">" + "ThreadDataLoad Wait - EXCEPTION CAUGHT.", e); 57 | } 58 | } 59 | m_Logger.log( Level.FINE, "ThreadDataLoad Wait - No longer running: " + this); 60 | } 61 | } 62 | // Handler to notify when load completes 63 | DataLoadCompleteHandler m_CompleteHandler; 64 | 65 | // Thread Handler for resynchronization 66 | public static abstract class DataLoadCompleteHandler 67 | { 68 | private Object m_Object; 69 | public DataLoadCompleteHandler(Object obj) 70 | { 71 | m_Object = obj; 72 | } 73 | public abstract void dataLoadComplete(Object obj, String message); 74 | public abstract void exceptionRaised(String message); 75 | 76 | public Object getM_Object() 77 | { 78 | return m_Object; 79 | } 80 | } 81 | 82 | public ThreadDataLoad(DataLoadBase dataLoader, String threadName) 83 | { 84 | m_LoadRunning = true; // Initialise the thread in running state 85 | m_LoadThread = new Thread(this); 86 | m_DataLoader = dataLoader; 87 | m_CompleteHandler = null; 88 | m_ThreadNameString = threadName; 89 | 90 | // Thread synchronization 91 | m_Lock = new Object(); 92 | } 93 | 94 | public void loadDBResults(DataLoadCompleteHandler completeHandler) 95 | { 96 | m_CompleteHandler = completeHandler; 97 | m_LoadThread.start(); 98 | } 99 | 100 | public void run() 101 | { 102 | m_LoadRunning = true; 103 | synchronized(m_Lock) 104 | { 105 | // Launch the data load read method 106 | try 107 | { 108 | m_DataLoader.loadDBResults(); 109 | m_Logger.log(Level.INFO, "Thread Name '" + m_ThreadNameString + "' has loaded : " + 110 | m_DataLoader.getRawEntryResultsFromDB().size() + " rows"); 111 | } 112 | 113 | catch (ClassNotFoundException | SQLException | IOException e) 114 | { 115 | m_CompleteHandler.exceptionRaised("Thread Exception: " + e.getLocalizedMessage()); 116 | } 117 | finally 118 | { 119 | m_CompleteHandler.dataLoadComplete(m_CompleteHandler.getM_Object(), ""); 120 | } 121 | m_LoadRunning = false; 122 | m_Lock.notifyAll(); 123 | 124 | // Kill the thread 125 | // m_LoadThread.interrupt(); 126 | } 127 | } 128 | 129 | /** 130 | * @return the m_LoadRunning 131 | */ 132 | public Boolean getM_LoadRunning() { 133 | return m_LoadRunning; 134 | } 135 | 136 | /** 137 | * @param m_LoadRunning the m_LoadRunning to set 138 | */ 139 | public void setM_LoadRunning(Boolean m_LoadRunning) { 140 | this.m_LoadRunning = m_LoadRunning; 141 | } 142 | 143 | /** 144 | * @return the m_DataLoader 145 | */ 146 | public synchronized DataLoadBase getM_DataLoader() { 147 | return m_DataLoader; 148 | } 149 | 150 | /** 151 | * @param m_DataLoader the m_DataLoader to set 152 | */ 153 | public synchronized void setM_DataLoader(DataLoadBase m_DataLoader) { 154 | this.m_DataLoader = m_DataLoader; 155 | } 156 | 157 | /** 158 | * @return the m_ThreadNameString 159 | */ 160 | public synchronized String getM_ThreadNameString() { 161 | return m_ThreadNameString; 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /src/test/java/loader/BaseTestEntry.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.net.URISyntaxException; 6 | import java.net.URL; 7 | import java.net.UnknownHostException; 8 | import java.sql.SQLException; 9 | import java.text.ParseException; 10 | import java.text.SimpleDateFormat; 11 | import java.time.LocalDateTime; 12 | import java.time.ZoneOffset; 13 | import java.time.format.DateTimeFormatter; 14 | import java.util.ArrayList; 15 | import org.junit.jupiter.api.Assertions; 16 | import org.junit.runner.RunWith; 17 | import org.mockito.junit.MockitoJUnitRunner; 18 | import control.MyLogger; 19 | import control.PrefsNightScoutLoader; 20 | import entity.DBResult; 21 | import entity.DBResultEntry; 22 | 23 | @RunWith(MockitoJUnitRunner.class) 24 | public abstract class BaseTestEntry { 25 | 26 | protected static Double DOUBLE_THRESHOLD = 0.001; 27 | 28 | public BaseTestEntry() { 29 | try { 30 | MyLogger.setup(true); 31 | } catch (IOException e) { 32 | // TODO Auto-generated catch block 33 | e.printStackTrace(); 34 | } 35 | } 36 | 37 | protected abstract Object[][] getExpectedTestResults(); 38 | protected abstract String getResourceFileName(); 39 | protected abstract DataLoadFile getDataLoadFile(); 40 | protected abstract SimpleDateFormat getSimpleDateFormat(); 41 | protected abstract String getDateFormat(); 42 | 43 | public ArrayList getDBResultArrayList() 44 | { 45 | return getDataLoadFile().getResultTreatments(); 46 | } 47 | 48 | public ArrayList getDBResultEntryArrayList() 49 | { 50 | return getDataLoadFile().getRawEntryResultsFromDB(); 51 | } 52 | 53 | public void performTestLoad() 54 | { 55 | doDataLoad(); 56 | DataLoadFile dataLoadDiasend = getDataLoadFile(); 57 | Assertions.assertTrue(dataLoadDiasend != null); 58 | try { 59 | assertionTests(dataLoadDiasend); 60 | } catch (ParseException e) { 61 | // TODO Auto-generated catch block 62 | e.printStackTrace(); 63 | } 64 | } 65 | 66 | 67 | public void doDataLoad() 68 | { 69 | // This disables any MongoDB connection attempts 70 | PrefsNightScoutLoader.getInstance().setM_NightscoutMongoServer(""); 71 | 72 | // Disable inferring any temp basals 73 | PrefsNightScoutLoader.getInstance().setM_InferTempBasals(false); 74 | 75 | URL url = this.getClass().getClassLoader().getResource(getResourceFileName()); 76 | Assertions.assertTrue(url != null); 77 | 78 | DataLoadFile dataLoadDiasend = getDataLoadFile(); 79 | try { 80 | dataLoadDiasend.initialize(new File(url.toURI()).getAbsolutePath()); 81 | dataLoadDiasend.loadDBResults(); 82 | } catch (URISyntaxException e) { 83 | Assertions.assertTrue(false, e.toString()); 84 | } catch (UnknownHostException e) { 85 | Assertions.assertTrue(false, e.toString()); 86 | } catch (ClassNotFoundException e) { 87 | Assertions.assertTrue(false, e.toString()); 88 | } catch (SQLException e) { 89 | Assertions.assertTrue(false, e.toString()); 90 | } catch (IOException e) { 91 | Assertions.assertTrue(false, e.toString()); 92 | } 93 | 94 | } 95 | 96 | 97 | private void assertionTests(DataLoadFile dataLoadDiasend) throws ParseException 98 | { 99 | Assertions.assertTrue(dataLoadDiasend != null); 100 | 101 | for (int c = 0; c < getExpectedTestResults().length; c++) 102 | { 103 | Object[] treatmentObject = getExpectedTestResults()[c]; 104 | int i = 0; 105 | 106 | // Integer indexInteger = (Integer) treatmentObject[i++]; 107 | String dateString = (String) treatmentObject[i++]; 108 | 109 | // Better way of date parsing Java 8 110 | DateTimeFormatter formatter = DateTimeFormatter.ofPattern(getDateFormat()); 111 | LocalDateTime parseDate = LocalDateTime.parse(dateString, formatter); 112 | long ldtEpoch = parseDate.toEpochSecond(ZoneOffset.UTC); 113 | 114 | 115 | Double bgDouble = (Double)treatmentObject[i++]; 116 | String dupeString = (String)treatmentObject[i++]; 117 | 118 | 119 | DBResultEntry result = dataLoadDiasend.getRawEntryResultHashMap().get(ldtEpoch * 1000); 120 | if (result != null) 121 | { 122 | String messgString = " for Entry " + c + " Date " + dateString + " Treatment Id: " + result.getIdentity(); 123 | Assertions.assertTrue(result != null); 124 | 125 | if (dupeString.equals("NO")) 126 | assertEquals(result.getM_BG(), bgDouble, 127 | "BG Differs" + messgString 128 | + " Result BG: " + result.getM_BG() 129 | + " Treatment BG: " + bgDouble); 130 | } 131 | 132 | } 133 | 134 | } 135 | 136 | protected void assertEquals(Double dbl1, Double dbl2, String messageString) 137 | { 138 | Assertions.assertTrue(Math.abs(dbl1 - dbl2) < DOUBLE_THRESHOLD, messageString); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultRoche.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | import java.text.ParseException; 6 | //import java.util.logging.Logger; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | import control.MyLogger; 11 | import utils.CommonUtils; 12 | 13 | public class DBResultRoche extends DBResult 14 | { 15 | // private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 16 | protected static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 17 | 18 | private boolean m_Valid = true; 19 | 20 | static private String[] m_FieldNames = 21 | { 22 | "Year", 23 | "Month", 24 | "Day", 25 | "DayName", 26 | "Time", 27 | "TimeSlot", 28 | "Result", 29 | "ResultType", 30 | "MealType", 31 | "Duration", 32 | }; 33 | 34 | static private boolean m_indexesInitialized = false; 35 | static private int m_YearIndex = 0; 36 | static private int m_MonthIndex = 0; 37 | static private int m_DayIndex = 0; 38 | static private int m_DayNameIndex = 0; 39 | static private int m_TimeIndex = 0; 40 | static private int m_TimeSlotIndex = 0; 41 | static private int m_ResultIndex = 0; 42 | static private int m_ResultTypeIndex = 0; 43 | static private int m_MealTypeIndex = 0; 44 | static private int m_DurationIndex = 0; 45 | 46 | 47 | 48 | 49 | public DBResultRoche(ResultSet rs) throws SQLException 50 | { 51 | super(); 52 | 53 | // Get this error if try to check resultset: 54 | // We just caught an error: The requested operation is not supported on forward only result sets. - The requested operation is not supported on forward only result sets. 55 | 56 | m_Year = rs.getInt("Year"); 57 | m_Month = rs.getInt("Month"); 58 | m_Day = rs.getInt("Day"); 59 | m_DayName = rs.getString("DayName"); 60 | m_Time = rs.getTimestamp("Time"); 61 | m_TimeSlot = rs.getString("TimeSlot"); 62 | m_Result = rs.getString("Result"); 63 | m_ResultType = rs.getString("ResultType"); 64 | m_MealType = rs.getString("MealType"); 65 | m_Duration = rs.getString("Duration"); 66 | } 67 | 68 | public DBResultRoche(String[] recordSet) 69 | { 70 | super(); 71 | 72 | if (m_indexesInitialized == false) 73 | { 74 | m_Valid = false; 75 | } 76 | 77 | initialize(); 78 | 79 | // Check for a repeat load and seeing the header line again. 80 | if (recordSet[m_YearIndex].equals("Year")) 81 | 82 | { 83 | m_Valid = false; 84 | } 85 | 86 | try 87 | { 88 | if (m_Valid == true) 89 | { 90 | m_Year = Integer.parseInt(recordSet[m_YearIndex]); 91 | m_Month = Integer.parseInt(recordSet[m_MonthIndex]); 92 | m_Day = Integer.parseInt(recordSet[m_DayIndex]); 93 | m_DayName = recordSet[m_DayNameIndex]; 94 | //m_Time = parseFileDate(recordSet[m_TimeIndex]); 95 | m_Time = CommonUtils.convertDateString(recordSet[m_TimeIndex]); 96 | m_TimeSlot = recordSet[m_TimeSlotIndex]; 97 | m_Result = recordSet[m_ResultIndex]; 98 | m_ResultType = recordSet[m_ResultTypeIndex]; 99 | m_MealType = recordSet[m_MealTypeIndex]; 100 | m_Duration = recordSet[m_DurationIndex]; 101 | 102 | // If meal type or duration == "null" then reset strings to empty 103 | if (m_MealType.equals("(null)")) 104 | { 105 | m_MealType = ""; 106 | } 107 | if (m_Duration.equals("(null)")) 108 | { 109 | m_Duration = ""; 110 | } 111 | 112 | String rawString = rawToString(); 113 | m_Logger.log(Level.FINE, "Just processed: " + rawString); 114 | 115 | } 116 | } 117 | catch (ParseException e) 118 | { 119 | m_Valid = false; 120 | } 121 | } 122 | 123 | public DBResultRoche() 124 | { 125 | super(); 126 | } 127 | 128 | private void initialize() 129 | { 130 | // Set values in underdlying ResultFromDB from record set 131 | if (m_indexesInitialized == false) 132 | { 133 | m_YearIndex = fieldLocation("Year"); 134 | m_MonthIndex = fieldLocation("Month"); 135 | m_DayIndex = fieldLocation("Day"); 136 | m_DayNameIndex = fieldLocation("DayName"); 137 | m_TimeIndex = fieldLocation("Time"); 138 | m_TimeSlotIndex = fieldLocation("TimeSlot"); 139 | m_ResultIndex = fieldLocation("Result"); 140 | m_ResultTypeIndex = fieldLocation("ResultType"); 141 | m_MealTypeIndex = fieldLocation("MealType"); 142 | m_DurationIndex = fieldLocation("Duration"); 143 | 144 | m_indexesInitialized = true; 145 | } 146 | } 147 | 148 | private int fieldLocation(String f) 149 | { 150 | int result=-1; 151 | for (int i=0; result < 0 && i < m_FieldNames.length; i++) 152 | { 153 | if (m_FieldNames[i] == f) 154 | { 155 | result=i; 156 | } 157 | } 158 | return result; 159 | } 160 | 161 | @Override 162 | public boolean isValid() 163 | { 164 | return m_Valid; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultEntryLibreView.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import java.text.ParseException; 4 | import java.util.Date; 5 | import java.util.HashMap; 6 | import com.mongodb.DBObject; 7 | import loader.AuditHistory; 8 | import utils.CommonUtils; 9 | import loader.DataLoadLibreView; 10 | 11 | public class DBResultEntryLibreView extends DBResultEntry 12 | { 13 | 14 | // Collection of items to handle the CGM tab 15 | static private boolean m_CGMIndexesInitialized = false; 16 | static private String[] m_CGMFieldNames = 17 | { 18 | // These field names are stripped of space 19 | "Device Timestamp", 20 | "Historic Glucose mmol/L", 21 | "Scan Glucose mmol/L" 22 | }; 23 | static private int m_CGMTimeIndex = 0; 24 | static private int m_HistoricCGMBGIndex = 0; 25 | static private int m_ScanCGMBGIndex = 0; 26 | 27 | protected boolean m_Valid = false; 28 | 29 | 30 | public DBResultEntryLibreView(DBObject rs) { 31 | super(rs); 32 | // TODO Auto-generated constructor stub 33 | } 34 | 35 | public DBResultEntryLibreView(String m_ID, Double m_Unfiltered, Double m_Filtered, String m_Direction, String m_Device, 36 | Double m_RSSI, Double m_SGV, String m_DateString, String m_Type, Double m_Date, Integer m_Noise) throws ParseException 37 | { 38 | super(m_ID, m_Unfiltered, m_Filtered, m_Direction, m_Device, 39 | m_RSSI, m_SGV, m_DateString, m_Type, m_Date, m_Noise); 40 | } 41 | 42 | public DBResultEntryLibreView(String[] row) 43 | { 44 | // Handle aa CGM record 45 | loadRawCGM(row); 46 | } 47 | 48 | public static void resetCGMHeaders() 49 | { 50 | m_CGMIndexesInitialized = false; 51 | } 52 | 53 | public static Boolean initializeCGMHeaders(String[] row) 54 | { 55 | Boolean result = false; 56 | 57 | if (m_CGMIndexesInitialized == false) 58 | { 59 | m_CGMTimeIndex = -1; 60 | m_HistoricCGMBGIndex = -1; 61 | m_ScanCGMBGIndex = -1; 62 | 63 | if (row.length >= m_CGMFieldNames.length) 64 | { 65 | HashMap fieldPosHashMap = new HashMap(); 66 | 67 | for (int i = 0; i < row.length; i++) 68 | { 69 | fieldPosHashMap.put(row[i], Integer.valueOf(i)); 70 | } 71 | 72 | for (int i = 0; i < m_CGMFieldNames.length; i++) 73 | { 74 | Integer posInteger = fieldPosHashMap.get(m_CGMFieldNames[i]); 75 | if (posInteger != null) 76 | { 77 | switch (i) 78 | { 79 | case 0 : m_CGMTimeIndex = posInteger.intValue(); break; 80 | case 1 : m_HistoricCGMBGIndex = posInteger.intValue(); break; 81 | case 2 : m_ScanCGMBGIndex = posInteger.intValue(); break; 82 | default : break; 83 | } 84 | } 85 | } 86 | 87 | m_CGMIndexesInitialized = true; 88 | } 89 | } 90 | result = (m_CGMTimeIndex != -1) && (m_HistoricCGMBGIndex != -1) && (m_ScanCGMBGIndex != -1) ? true : false; 91 | 92 | return result; 93 | } 94 | 95 | private void loadRawCGM(String[] row) 96 | { 97 | String timeStr = row[m_CGMTimeIndex]; 98 | Double historicBGDouble = getBGValue(m_HistoricCGMBGIndex, row); 99 | Double scanBGDouble = getBGValue(m_ScanCGMBGIndex, row); 100 | Double bgValueDouble = historicBGDouble == null ? scanBGDouble : historicBGDouble; 101 | 102 | m_Device = AuditHistory.getInstance().getM_NextUploadID(); 103 | // Boolean scannedValBoolean = scanBGDouble == null ? false : true; // Would like to mark this as a scan but have nowhere to put it 104 | 105 | m_Type = "sgv"; 106 | if (bgValueDouble != null) 107 | { 108 | m_SGV = bgValueDouble * 18; // Values held in mgDl 109 | m_BG = bgValueDouble; 110 | } 111 | 112 | if (timeStr != null) 113 | { 114 | setM_UTCDateTime(DataLoadLibreView.parseFileLocalDateTime(timeStr)); 115 | 116 | Date d = new Date(0); 117 | // d = parseFileDate(timeStr); 118 | d = DataLoadLibreView.parseFileDateTime(timeStr); 119 | if (d.getTime() != 0) 120 | { 121 | //This isn't working, it's applying the offset twice, I suspect something to 122 | //do with Date.getTime() always returning results for display in local TZ 123 | //Date utcD = new Date(CommonUtils.toUTC(d.getTime())); 124 | Date utcD = new Date(d.getTime()); 125 | this.setM_UTCDate(utcD); 126 | 127 | try { 128 | this.setM_DateString(CommonUtils.convertDateString(d, "dd/MM/yyyy HH:mm:ss")); 129 | } catch (ParseException e) { 130 | m_Logger.severe("Error converting Date to NSZDateString : " + timeStr); 131 | 132 | // TODO Auto-generated catch block 133 | e.printStackTrace(); 134 | } 135 | 136 | 137 | // Essential for use in comparator 138 | setEpochMilliesFromUTC(); 139 | } 140 | } 141 | 142 | m_Valid = (getM_BG() == null || getM_SGV() == null || getM_UTCDate() == null) ? false : true; 143 | } 144 | 145 | private Double getBGValue(int index, String[] rowStrings) 146 | { 147 | Double resultDouble = null; 148 | if (rowStrings.length >= index) 149 | { 150 | if (rowStrings[index] != null && rowStrings[index].length() > 0) 151 | { 152 | resultDouble = Double.parseDouble(rowStrings[index]); 153 | } 154 | } 155 | return resultDouble; 156 | } 157 | 158 | public boolean isValid() 159 | { 160 | return m_Valid; 161 | } 162 | 163 | /** 164 | * @return the m_CGMTimeIndex 165 | */ 166 | public static synchronized int getM_CGMTimeIndex() { 167 | return m_CGMTimeIndex; 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /src/main/java/loader/DataLoadLibreView.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.text.ParseException; 8 | import java.time.LocalDateTime; 9 | import java.util.Collections; 10 | import java.util.Date; 11 | import java.util.logging.Level; 12 | import java.util.logging.Logger; 13 | 14 | import control.MyLogger; 15 | import entity.DBResult; 16 | import entity.DBResultEntry; 17 | import entity.DBResultEntryLibreView; 18 | import entity.ResultFromDBComparator; 19 | import utils.CommonUtils; 20 | 21 | public class DataLoadLibreView extends DataLoadCSVFile 22 | { 23 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 24 | private static final String m_LibreViewSplitBy = ","; 25 | 26 | private static final String VARIABLE_STRING = "VARIES_BY_EXPORT_DO_NOT_COMPARE"; 27 | 28 | private static final String LINE_1_HEADERS[] = 29 | { 30 | "Glucose Data", 31 | "Generated on", 32 | "VARIES_BY_EXPORT_DO_NOT_COMPARE", 33 | "Generated by", 34 | "VARIES_BY_EXPORT_DO_NOT_COMPARE", 35 | 36 | }; 37 | 38 | private static final String LINE_2_HEADERS[] = 39 | { 40 | "Device", 41 | "Serial Number", 42 | "Device Timestamp", 43 | "Record Type", 44 | "Historic Glucose mmol/L", 45 | "Scan Glucose mmol/L", 46 | "Non-numeric Rapid-Acting Insulin", 47 | "Rapid-Acting Insulin (units)", 48 | "Non-numeric Food", 49 | "Carbohydrates (grams)", 50 | "Carbohydrates (servings)", 51 | "Non-numeric Long-Acting Insulin", 52 | "Long-Acting Insulin Value (units)", 53 | "Notes", 54 | "Strip Glucose mmol/L", 55 | "Ketone mmol/L", 56 | "Meal Insulin (units)", 57 | "Correction Insulin (units)", 58 | "User Change Insulin (units)", 59 | }; 60 | 61 | public DataLoadLibreView() 62 | { 63 | m_SkipLines = 2; 64 | m_HeaderLine = 2; 65 | } 66 | 67 | static public Date parseFileDateTime(String date) 68 | { 69 | Date result = null; 70 | 71 | try { 72 | result = CommonUtils.convertDateString(date); 73 | } catch (ParseException e1) { 74 | m_Logger.log(Level.SEVERE, " " + "parseFileDate - Unexpected error parsing date: " + date); 75 | 76 | } 77 | return result; 78 | } 79 | 80 | static public LocalDateTime parseFileLocalDateTime(String date) 81 | { 82 | LocalDateTime result = null; 83 | 84 | try { 85 | result = CommonUtils.convertLocalDateTimeString(date); 86 | } catch (ParseException e1) { 87 | m_Logger.log(Level.SEVERE, " " + "parseFileLocalDateTime - Unexpected error parsing date: " + date); 88 | 89 | } 90 | return result; 91 | } 92 | 93 | 94 | @Override 95 | protected DBResult makeDBResult(String[] res) { 96 | return null; 97 | } 98 | 99 | @Override 100 | protected DBResultEntry makeDBResultEntry(String[] res) 101 | { 102 | DBResultEntry resultEntry = null; 103 | 104 | resultEntry = new DBResultEntryLibreView(res); 105 | 106 | return resultEntry; 107 | } 108 | 109 | @Override 110 | protected void initializeHeaders(String[] res) 111 | { 112 | DBResultEntryLibreView.initializeCGMHeaders(res); 113 | } 114 | 115 | @Override 116 | protected void resetCGMHeaders() 117 | { 118 | DBResultEntryLibreView.resetCGMHeaders(); 119 | } 120 | 121 | @Override 122 | protected void orderRawResults() 123 | { 124 | Collections.sort(rawResultsFromDB, new ResultFromDBComparator(false)); 125 | } 126 | 127 | @Override 128 | protected String loadStringName() 129 | { 130 | // TODO Auto-generated method stub 131 | return null; 132 | } 133 | 134 | @Override 135 | protected String getSplitBy() 136 | { 137 | return m_LibreViewSplitBy; 138 | } 139 | 140 | public static boolean isLibreView(String fileName) 141 | { 142 | boolean result = true; // Assume it is to start with 143 | BufferedReader br = null; 144 | String line = ""; 145 | String cvsSplitBy = m_LibreViewSplitBy; 146 | 147 | int ln = 0; 148 | int maxLines = 2; 149 | 150 | try 151 | { 152 | br = new BufferedReader(new FileReader(fileName)); 153 | while (result && (ln <= maxLines) && (line = br.readLine()) != null) 154 | { 155 | ln++; 156 | // use comma as separator 157 | String[] rs = line.split(cvsSplitBy); 158 | 159 | result = ln == 1 ? doesLineMatch(rs, LINE_1_HEADERS, VARIABLE_STRING) : result; 160 | result = ln == 2 ? doesLineMatch(rs, LINE_2_HEADERS, VARIABLE_STRING) : result; 161 | } 162 | 163 | } 164 | catch (FileNotFoundException e) 165 | { 166 | m_Logger.log(Level.SEVERE, "" + "isLibreView: FileNotFoundException. File " + fileName + " Error " + e.getMessage()); 167 | 168 | e.printStackTrace(); 169 | } 170 | catch (IOException e) 171 | { 172 | m_Logger.log(Level.SEVERE, "" + "isLibreView: IOException. File " + fileName + " Error " + e.getMessage()); 173 | e.printStackTrace(); 174 | } 175 | finally 176 | { 177 | if (br != null) 178 | { 179 | try 180 | { 181 | br.close(); 182 | } 183 | catch (IOException e) 184 | { 185 | m_Logger.log(Level.SEVERE, "" + "isLibreView: IOException closing file. File " + fileName + " Error " + e.getMessage()); 186 | e.printStackTrace(); 187 | } 188 | } 189 | } 190 | 191 | return result; 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultEntryDiasend.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import java.text.ParseException; 4 | import java.util.Date; 5 | import org.apache.poi.hssf.usermodel.HSSFRow; 6 | 7 | import com.mongodb.DBObject; 8 | 9 | import loader.AuditHistory; 10 | import utils.CommonUtils; 11 | import loader.DataLoadDiasend; 12 | 13 | public class DBResultEntryDiasend extends DBResultEntry 14 | { 15 | // Collection of items to handle the CGM tab 16 | static private boolean m_CGMIndexesInitialized = false; 17 | static private String[] m_CGMFieldNames = 18 | { 19 | "Time", 20 | "mmol/L mg/dl", // We can see either string come through 21 | "", // This field is empty 22 | "Serial number" 23 | }; 24 | static private int m_CGMTimeIndex = 0; 25 | static private int m_CGMBGIndex = 0; 26 | 27 | 28 | public DBResultEntryDiasend(DBObject rs) { 29 | super(rs); 30 | // TODO Auto-generated constructor stub 31 | } 32 | 33 | public DBResultEntryDiasend(String m_ID, Double m_Unfiltered, Double m_Filtered, String m_Direction, String m_Device, 34 | Double m_RSSI, Double m_SGV, String m_DateString, String m_Type, Double m_Date, Integer m_Noise) throws ParseException 35 | { 36 | super(m_ID, m_Unfiltered, m_Filtered, m_Direction, m_Device, 37 | m_RSSI, m_SGV, m_DateString, m_Type, m_Date, m_Noise); 38 | } 39 | 40 | public DBResultEntryDiasend(HSSFRow row) 41 | { 42 | // Handle aa CGM record 43 | loadRawCGM(row); 44 | } 45 | 46 | public static void resetCGMHeaders() 47 | { 48 | m_CGMIndexesInitialized = false; 49 | } 50 | 51 | public static Boolean initializeCGMHeaders(HSSFRow row) 52 | { 53 | Boolean result = false; 54 | 55 | if (m_CGMIndexesInitialized == false) 56 | { 57 | m_CGMTimeIndex = -1; 58 | m_CGMBGIndex = -1; 59 | 60 | int maxColumns = row.getPhysicalNumberOfCells(); 61 | 62 | // Diasend now has an empty column 63 | int cols = 0; 64 | for (int i = 0; i < m_CGMFieldNames.length; i++) cols += m_CGMFieldNames[i].length() > 0 ? 1 : 0; 65 | 66 | if (maxColumns >= cols) 67 | { 68 | int c = 0; 69 | 70 | for (c=0; c < m_CGMFieldNames.length; c++) 71 | { 72 | if (row.getCell(c) != null) 73 | { 74 | String cell = row.getCell(c).getStringCellValue(); 75 | if (m_CGMFieldNames[c].contains(cell)) 76 | { 77 | switch (c) 78 | { 79 | case 0 : m_CGMTimeIndex = c; break; 80 | case 1 : m_CGMBGIndex = c; break; 81 | default : break; 82 | } 83 | } 84 | } 85 | } 86 | m_CGMIndexesInitialized = true; 87 | } 88 | } 89 | 90 | result = (m_CGMTimeIndex != -1) && (m_CGMBGIndex != -1) ? true : false; 91 | 92 | return result; 93 | } 94 | 95 | private void loadRawCGM(HSSFRow row) 96 | { 97 | String timeStr = CommonUtils.getStringCellValue(row, m_CGMTimeIndex); 98 | Double bgDouble = CommonUtils.getDoubleCellValue(row, m_CGMBGIndex); 99 | 100 | m_Device = AuditHistory.getInstance().getM_NextUploadID(); 101 | 102 | m_Type = "sgv"; 103 | if (bgDouble != null) 104 | { 105 | m_SGV = bgDouble * 18; // Values held in mgDl 106 | m_BG = bgDouble; 107 | } 108 | 109 | if (timeStr != null) 110 | { 111 | Date d = new Date(0); 112 | // d = parseFileDate(timeStr); 113 | d = DataLoadDiasend.parseFileDateTime(timeStr); 114 | if (d.getTime() != 0) 115 | { 116 | //This isn't working, it's applying the offset twice, I suspect something to 117 | //do with Date.getTime() always returning results for display in local TZ 118 | //Date utcD = new Date(CommonUtils.toUTC(d.getTime())); 119 | Date utcD = new Date(d.getTime()); 120 | this.setM_UTCDate(utcD); 121 | 122 | try { 123 | this.setM_DateString(CommonUtils.convertNSZDateString(d)); 124 | } catch (ParseException e) { 125 | m_Logger.severe("Error converting Date to NSZDateString : " + timeStr); 126 | } 127 | 128 | 129 | // Essential for use in comparator 130 | setEpochMilliesFromUTC(); 131 | } 132 | } 133 | } 134 | 135 | /** 136 | * @return the m_CGMTimeIndex 137 | */ 138 | public static synchronized int getM_CGMTimeIndex() { 139 | return m_CGMTimeIndex; 140 | } 141 | 142 | // private Date parseFileDateTime(String date) 143 | // { 144 | // Date result = new Date(0); 145 | // // Combined Date Time 146 | // 147 | //// final String defSlashFormat = new String("dd/MM/yy HH:mm"); -- Changed with Glooko? 148 | // // In fact, now find that it changes between dd/MM/yyyy and MM/dd/yyyy, so we hold a preference 149 | // // and set the preference during an initial file scan 150 | // 151 | // final String defSlashFormat = new String( 152 | // PrefsNightScoutLoader.getInstance().getM_DiasendDateFormat() + " HH:mm"); 153 | // 154 | // String prefDateFormat = PrefsNightScoutLoader.getInstance().getM_InputDateFormat(); 155 | // DateFormat slashformat = new SimpleDateFormat((prefDateFormat.contains("/") ? prefDateFormat : defSlashFormat), Locale.ENGLISH); 156 | // // DateFormat slashformat = new SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.ENGLISH); 157 | // 158 | // try 159 | // { 160 | // result = slashformat.parse(date); 161 | // } 162 | // catch (ParseException e) 163 | // { 164 | // m_Logger.log(Level.SEVERE, "<"+this.getClass().getName()+"> " + "parseFileDate - Unexpected error parsing date: " + date); 165 | // } 166 | // 167 | // return result; 168 | // } 169 | 170 | 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/win/WinTextWin.java: -------------------------------------------------------------------------------- 1 | package win; 2 | import java.awt.BorderLayout; 3 | import java.awt.EventQueue; 4 | 5 | import javax.swing.JPanel; 6 | import java.awt.FlowLayout; 7 | import java.awt.Font; 8 | 9 | import javax.swing.JFileChooser; 10 | import javax.swing.JFrame; 11 | import javax.swing.JMenu; 12 | import javax.swing.JMenuBar; 13 | import javax.swing.JMenuItem; 14 | import javax.swing.border.EmptyBorder; 15 | import javax.swing.filechooser.FileNameExtensionFilter; 16 | 17 | import control.MyLogger; 18 | import entity.TextLineReceiverInterface; 19 | 20 | import javax.swing.JTextArea; 21 | import java.awt.event.ActionListener; 22 | import java.awt.event.MouseAdapter; 23 | import java.awt.event.MouseEvent; 24 | import java.io.IOException; 25 | import java.io.PrintWriter; 26 | import java.util.ArrayList; 27 | import java.util.logging.Level; 28 | import java.util.logging.Logger; 29 | import java.awt.event.ActionEvent; 30 | import javax.swing.JScrollPane; 31 | import javax.swing.JSeparator; 32 | 33 | // public class WinTextWin extends JDialog implements TextLineReceiverInterface 34 | public class WinTextWin extends JFrame implements TextLineReceiverInterface 35 | { 36 | 37 | /** 38 | * 39 | */ 40 | private static final long serialVersionUID = -51832866421758739L; 41 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 42 | 43 | private final JPanel contentPanel = new JPanel(); 44 | private JTextArea txtrNightscoutloader = new JTextArea(); 45 | 46 | private String m_Text; 47 | private ArrayList m_AppendedLines; 48 | 49 | protected JMenuBar m_MenuBar; 50 | protected JMenu m_mnFile; 51 | protected JMenuItem m_mntmFileSave; 52 | protected JMenuItem m_mntmFileClose; 53 | protected boolean m_Enabled; 54 | 55 | 56 | /** 57 | * Create the dialog. 58 | */ 59 | public WinTextWin(String title) 60 | { 61 | super.setTitle(title); 62 | 63 | // URL url = MainNightScoutLoader.class.getResource("/Nightscout.jpg"); 64 | // ImageIcon img = new ImageIcon(url); 65 | // setIconImage(img.getImage()); 66 | 67 | m_MenuBar = new JMenuBar(); 68 | setJMenuBar(m_MenuBar); 69 | 70 | m_mnFile = new JMenu("File"); 71 | m_mnFile.addMouseListener(new MouseAdapter() { 72 | @Override 73 | public void mouseClicked(MouseEvent arg0) 74 | { 75 | // Nothing needed here 76 | } 77 | }); 78 | 79 | m_MenuBar.add(m_mnFile); 80 | 81 | m_mntmFileSave = new JMenuItem("Save Text"); 82 | m_mntmFileSave.addActionListener(new ActionListener() { 83 | public void actionPerformed(ActionEvent e) 84 | { 85 | doSaveText(); 86 | } 87 | }); 88 | m_mnFile.add(m_mntmFileSave); 89 | m_mnFile.add(new JSeparator()); // SEPARATOR 90 | 91 | m_mntmFileClose = new JMenuItem("Close"); 92 | m_mntmFileClose.addActionListener(new ActionListener() { 93 | public void actionPerformed(ActionEvent e) 94 | { 95 | setVisible(false); 96 | } 97 | }); 98 | m_mnFile.add(m_mntmFileClose); 99 | 100 | 101 | m_Text = new String(); 102 | m_AppendedLines = new ArrayList(); 103 | 104 | setBounds(100, 100, 750, 620); 105 | getContentPane().setLayout(new BorderLayout()); 106 | contentPanel.setLayout(new FlowLayout()); 107 | contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); 108 | getContentPane().add(contentPanel, BorderLayout.CENTER); 109 | 110 | Font font = new Font("Courier", Font.BOLD, 12); 111 | 112 | getContentPane().add(txtrNightscoutloader, BorderLayout.WEST); 113 | txtrNightscoutloader.setFont(font); 114 | 115 | JScrollPane scrollPane = new JScrollPane(txtrNightscoutloader); 116 | getContentPane().add(scrollPane, BorderLayout.CENTER); 117 | } 118 | 119 | public void setText(String text) 120 | { 121 | m_Text = text; 122 | txtrNightscoutloader.setText(m_Text); 123 | } 124 | 125 | @Override 126 | public void addTextLine(String line) 127 | { 128 | m_Text += line; 129 | m_AppendedLines.add(line); 130 | 131 | // Do this in the GUI thread 132 | EventQueue.invokeLater(new 133 | Runnable() 134 | { 135 | public void run() 136 | { 137 | String line = null; 138 | if (m_AppendedLines.size() > 0) 139 | { 140 | line = m_AppendedLines.get(0); 141 | txtrNightscoutloader.append(line); 142 | m_AppendedLines.remove(0); 143 | } 144 | } 145 | }); 146 | } 147 | 148 | protected void setMenusEnabled(JMenu m) 149 | { 150 | for (int i = 0; i < m.getItemCount(); i++) 151 | { 152 | JMenuItem mi = m.getItem(i); 153 | if (mi != null) 154 | { 155 | mi.setEnabled(m_Enabled); 156 | } 157 | } 158 | } 159 | 160 | 161 | private void doSaveText() 162 | { 163 | // Popup a dialog to select the file for saving contents to 164 | JFileChooser chooser = new JFileChooser(); 165 | FileNameExtensionFilter filter = new FileNameExtensionFilter( 166 | "Text Files", "txt"); 167 | chooser.setFileFilter(filter); 168 | // File selectedFile = new File(PrefsNightScoutLoader.getInstance().getM_AnalysisFilePath()); 169 | // chooser.setSelectedFile(selectedFile); 170 | int returnVal = chooser.showOpenDialog(getContentPane()); 171 | if(returnVal == JFileChooser.APPROVE_OPTION) 172 | { 173 | m_Logger.log(Level.INFO, "You chose to Save to this file: " + 174 | chooser.getSelectedFile().getAbsolutePath()); 175 | 176 | try 177 | { 178 | PrintWriter writer = new PrintWriter(chooser.getSelectedFile().getAbsolutePath(), "UTF-8"); 179 | writer.print(m_Text); 180 | 181 | writer.close(); 182 | } 183 | catch (IOException e) 184 | { 185 | // do something 186 | } 187 | } 188 | 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/mongo/NightscoutMongoDB.java: -------------------------------------------------------------------------------- 1 | package mongo; 2 | 3 | import java.lang.management.ManagementFactory; 4 | import java.lang.management.RuntimeMXBean; 5 | import java.util.List; 6 | import org.bson.Document; 7 | 8 | import com.mongodb.DB; 9 | import com.mongodb.DBCollection; 10 | import com.mongodb.MongoClient; 11 | import com.mongodb.MongoClientURI; 12 | import com.mongodb.WriteConcern; 13 | import com.mongodb.client.MongoCollection; 14 | import com.mongodb.client.MongoDatabase; 15 | import control.PrefsNightScoutLoader; 16 | 17 | public class NightscoutMongoDB { 18 | 19 | private final String m_MongoHost = PrefsNightScoutLoader.getInstance().getM_NightscoutMongoServer(); 20 | private final String m_MongoDB = PrefsNightScoutLoader.getInstance().getM_NightscoutMongoDB(); 21 | private final String m_TreatmentsCollection = PrefsNightScoutLoader.getInstance().getM_NightscoutMongoCollection(); 22 | private final String m_RocheDebugCollection = PrefsNightScoutLoader.getInstance().getM_MongoMeterCollection(); 23 | private final String m_AuditCollection = PrefsNightScoutLoader.getInstance().getM_NightscoutAuditCollection(); 24 | private final String m_SensorCollection = PrefsNightScoutLoader.getInstance().getM_NightscoutSensorMongoCollection(); 25 | private final String m_ProfileCollection = PrefsNightScoutLoader.getInstance().getM_NightscoutProfileCollection(); 26 | 27 | private MongoClient m_DbClient = null; 28 | private DB m_Db = null; 29 | private MongoDatabase m_MongoDatabase = null; 30 | 31 | private Boolean m_TLSValidBoolean = false; 32 | 33 | public NightscoutMongoDB() 34 | { 35 | initialise(); 36 | } 37 | 38 | public NightscoutMongoDB(String mongoHost) 39 | { 40 | initialise(mongoHost); 41 | } 42 | 43 | public NightscoutMongoDB(String mongoHost, String mongoDB) 44 | { 45 | initialise(mongoHost, mongoDB); 46 | } 47 | 48 | // Original V2.x interface used when NightscoutLoader was first written 2015 49 | public DBCollection getTreatmentsV2xCollection() 50 | { 51 | return m_Db.getCollection(m_TreatmentsCollection); 52 | } 53 | 54 | public DBCollection getAuditV2xCollection() 55 | { 56 | return m_Db.getCollection(m_AuditCollection); 57 | } 58 | 59 | public DBCollection getSensorV2xCollection() 60 | { 61 | return m_Db.getCollection(m_SensorCollection); 62 | } 63 | 64 | public DBCollection getRocheDebugMeterV2xCollection() 65 | { 66 | return m_Db.getCollection(m_RocheDebugCollection); 67 | } 68 | 69 | public DBCollection getProfileCollectionV2xCollection() 70 | { 71 | return m_Db.getCollection(m_ProfileCollection); 72 | } 73 | 74 | 75 | 76 | // V3.0.0 interface 77 | public MongoCollection getTreatmentsCollection() 78 | { 79 | return m_MongoDatabase.getCollection(m_TreatmentsCollection); 80 | } 81 | 82 | public MongoCollection getAuditCollection() 83 | { 84 | return m_MongoDatabase.getCollection(m_AuditCollection); 85 | } 86 | 87 | public MongoCollection getSensorCollection() 88 | { 89 | return m_MongoDatabase.getCollection(m_SensorCollection); 90 | } 91 | 92 | public MongoCollection getRocheDebugMeterCollection() 93 | { 94 | return m_MongoDatabase.getCollection(m_RocheDebugCollection); 95 | } 96 | 97 | public MongoCollection getProfileCollectionCollection() 98 | { 99 | return m_MongoDatabase.getCollection(m_ProfileCollection); 100 | } 101 | 102 | public void close() 103 | { 104 | m_DbClient.close(); 105 | } 106 | 107 | private void initialise() 108 | { 109 | initialise(m_MongoHost, m_MongoDB); 110 | } 111 | 112 | private void initialise(String mongoHost) 113 | { 114 | initialise(mongoHost, null); 115 | } 116 | 117 | 118 | @SuppressWarnings("deprecation") 119 | private void initialise(String mongoHost, String mongoDB) 120 | { 121 | initialiseTLSValid(); 122 | 123 | MongoClientURI dbURI; 124 | 125 | if (mongoHost.contains("@")) 126 | { 127 | // Create full URI with DB too. This is straight from the https://mongolab.com/databases/dexcom_db page 128 | // dbURI = new MongoClientURI(m_MongoHost + ":" + mongoPort + "/" + mongoDB); 129 | 130 | // Left like below after a few days not using server but not working clearly :-( 131 | //dbURI = new MongoClientURI(m_MongoHost + ":" + "/" + mongoDB); 132 | 133 | dbURI = new MongoClientURI(mongoHost); 134 | m_DbClient = new MongoClient(dbURI); 135 | } 136 | else 137 | { 138 | m_DbClient = new MongoClient(mongoHost); 139 | } 140 | 141 | if (mongoDB != null) 142 | { 143 | m_Db = m_DbClient.getDB(mongoDB); 144 | 145 | m_MongoDatabase = m_DbClient.getDatabase(mongoDB).withWriteConcern(WriteConcern.MAJORITY); 146 | } 147 | } 148 | 149 | private void initialiseTLSValid() 150 | { 151 | RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); 152 | List list = runtimeMxBean.getInputArguments(); 153 | 154 | for (String s : list) 155 | { 156 | m_TLSValidBoolean = s.contains("jdk.tls.client.protocols") && s.contains("TLSv1.2") ? true : m_TLSValidBoolean; 157 | } 158 | } 159 | 160 | /** 161 | * @return the m_DbClient 162 | */ 163 | public synchronized MongoClient getM_DbClient() { 164 | return m_DbClient; 165 | } 166 | 167 | /** 168 | * @return the m_Db 169 | */ 170 | public synchronized DB getM_Db() { 171 | return m_Db; 172 | } 173 | 174 | /** 175 | * @return the m_MongoDatabase 176 | */ 177 | public synchronized MongoDatabase getM_MongoDatabase() { 178 | return m_MongoDatabase; 179 | } 180 | 181 | /** 182 | * @return the m_TLSValidBoolean 183 | */ 184 | public synchronized Boolean getM_TLSValidBoolean() { 185 | return m_TLSValidBoolean; 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultCore.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import java.text.DateFormat; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | 7 | import com.mongodb.BasicDBObject; 8 | 9 | import control.PrefsNightScoutLoader; 10 | 11 | public abstract class DBResultCore implements DBResultInterface 12 | { 13 | // Sep 2016 14 | // Proximity checks are for where we have a new Meter/Pump entry coming into an 15 | // existing NightScout Care Portal data set, and there's a possible duplicate 16 | // among them. 17 | protected static boolean m_ProximityCheck = false; 18 | protected static boolean m_ProximityCheckSecondPass = false; 19 | 20 | // Proximity match with an existing record 21 | private boolean m_ProximityPossibleDuplicate = false; 22 | 23 | 24 | // Can only instantiate derived classes 25 | protected DBResultCore() 26 | { 27 | 28 | } 29 | 30 | public long getProximityAdjustedTime(long time) 31 | { 32 | long result = 0; 33 | 34 | if (m_ProximityCheck == true) 35 | { 36 | // How many minutes apart two entries can be before being considered proximity/duplicate 37 | int proximityMinutes = PrefsNightScoutLoader.getInstance().getM_ProximityMinutes(); 38 | 39 | // Since we may have 2 adjacent readings either side of the mid point of proximityMinutes, we do a second 40 | // pass looking for proximity matches but this time slide the time forward by half the proximityMinutes 41 | if (m_ProximityCheckSecondPass == true) 42 | { 43 | long halfProximityMinutesMillis = proximityMinutes * 60 * 1000 / 2; 44 | 45 | time += halfProximityMinutesMillis; 46 | } 47 | 48 | long roundPeriodMins = proximityMinutes * 60 * 1000; 49 | // Adjust time by rounding up or down to nearest proximity minutes approximately. 50 | 51 | long timeUp = time - (time % roundPeriodMins) + roundPeriodMins; 52 | long timeDown = time - (time % roundPeriodMins); 53 | 54 | // Are we closer to Up time or Down 55 | if ( (timeUp - time) > (time - timeDown) ) 56 | { 57 | result = timeDown; 58 | } 59 | else 60 | { 61 | result = timeUp; 62 | } 63 | } 64 | else 65 | { 66 | result = time; 67 | } 68 | 69 | return result; 70 | } 71 | 72 | static public void appendToDoc(BasicDBObject doc, String label, String value) 73 | { 74 | if (value.length() > 0) 75 | { 76 | doc.append(label, value); 77 | } 78 | } 79 | 80 | static public void appendToDoc(BasicDBObject doc, String label, Double value) 81 | { 82 | if (value != null) 83 | { 84 | doc.append(label, doubleIsInteger(value) ? value.longValue() : value.doubleValue()); 85 | } 86 | } 87 | 88 | static public void appendToDoc(BasicDBObject doc, String label, int value) 89 | { 90 | doc.append(label, value); 91 | } 92 | 93 | static public void appendToDoc(BasicDBObject doc, String label, Date value) 94 | { 95 | if (value != null) 96 | { 97 | // 16 Jun 2016 98 | // Feedback from Mel in Australia that times are shifted 99 | // Realise that I need to convert from local to UTC times! 100 | // final DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'", Locale.ENGLISH); 101 | // final DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH); // Try something different 102 | 103 | final DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); 104 | // Date utcValue = new Date(CommonUtils.toUTC(value.getTime(), CommonUtils.locTZ)); 105 | // String dVal = format.format(utcValue); 106 | 107 | String dVal = format.format(value); 108 | 109 | doc.append(label, dVal); 110 | } 111 | 112 | } 113 | 114 | static public boolean doubleIsInteger(double val) 115 | { 116 | boolean result = false; // Assume not initially 117 | 118 | if (val == Math.floor(val)) 119 | { 120 | result = true; 121 | } 122 | return result; 123 | } 124 | 125 | 126 | /** 127 | * @return the m_ProximityCheck 128 | */ 129 | public static synchronized boolean isM_ProximityCheck() { 130 | return m_ProximityCheck; 131 | } 132 | 133 | /** 134 | * @param m_ProximityCheck the m_ProximityCheck to set 135 | */ 136 | public static synchronized void setM_ProximityCheck(boolean proximityCheck) { 137 | DBResultCore.m_ProximityCheck = proximityCheck; 138 | } 139 | 140 | /** 141 | * @return the m_ProximityCheckSecondPass 142 | */ 143 | public static synchronized boolean isM_ProximityCheckSecondPass() { 144 | return m_ProximityCheckSecondPass; 145 | } 146 | 147 | /** 148 | * @param m_ProximityCheckSecondPass the m_ProximityCheckSecondPass to set 149 | */ 150 | public static synchronized void setM_ProximityCheckSecondPass(boolean proximityCheckSecondPass) { 151 | DBResultCore.m_ProximityCheckSecondPass = proximityCheckSecondPass; 152 | } 153 | 154 | /** 155 | * @return the m_ProximityPossibleDuplicate 156 | */ 157 | public synchronized boolean isM_ProximityPossibleDuplicate() 158 | { 159 | determineWhetherInProximity(); 160 | return m_ProximityPossibleDuplicate; 161 | } 162 | 163 | /** 164 | * @param m_ProximityPossibleDuplicate the m_ProximityPossibleDuplicate to set 165 | */ 166 | public synchronized void setM_ProximityPossibleDuplicate(boolean m_ProximityPossibleDuplicate) 167 | { 168 | this.m_ProximityPossibleDuplicate = m_ProximityPossibleDuplicate; 169 | 170 | // David - 31 Jan 2018 171 | // This caused java.lang.StackOverflowError 172 | // setImpactOfProximity(); 173 | } 174 | 175 | /** 176 | * @param m_ProximityPossibleDuplicate the m_ProximityPossibleDuplicate to set 177 | */ 178 | 179 | public synchronized boolean getM_ProximityPossibleDuplicate() 180 | { 181 | return this.m_ProximityPossibleDuplicate; 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | org.Nightscout.NightscoutLoader 9 | NightscoutLoaderMaven 10 | 0.0.1-SNAPSHOT 11 | 12 | NightscoutLoaderMaven 13 | A simple NightscoutLoaderMaven. 14 | https://david50703.wixsite.com/nightscoutloader 15 | 16 | 17 | UTF-8 18 | 1.8 19 | 1.8 20 | 21 | 22 | 23 | 24 | 25 | org.junit.jupiter 26 | junit-jupiter-api 27 | 5.8.1 28 | test 29 | 30 | 31 | 32 | org.junit.jupiter 33 | junit-jupiter-engine 34 | 5.8.1 35 | test 36 | 37 | 38 | 39 | 40 | 41 | org.apache.poi 42 | poi 43 | 3.13 44 | 45 | 46 | 47 | org.apache.poi 48 | poi-ooxml 49 | 3.13 50 | 51 | 52 | 53 | 54 | org.mongodb 55 | mongo-java-driver 56 | 3.12.10 57 | 58 | 59 | 60 | 61 | com.jcraft 62 | jsch 63 | 0.1.55 64 | 65 | 66 | 67 | 68 | com.googlecode.json-simple 69 | json-simple 70 | 1.1.1 71 | 72 | 73 | 74 | 75 | net.sourceforge.jdatepicker 76 | jdatepicker 77 | 1.3.2 78 | 79 | 80 | 81 | 82 | commons-cli 83 | commons-cli 84 | 1.4 85 | 86 | 87 | 88 | org.mockito 89 | mockito-core 90 | 2.23.4 91 | test 92 | 93 | 94 | 95 | 96 | 97 | 98 | 100 | 101 | 102 | maven-clean-plugin 103 | 3.1.0 104 | 105 | 106 | maven-site-plugin 107 | 3.7.1 108 | 109 | 110 | maven-project-info-reports-plugin 111 | 3.0.0 112 | 113 | 114 | 115 | 116 | maven-resources-plugin 117 | 3.0.2 118 | 119 | 120 | maven-compiler-plugin 121 | 3.8.0 122 | 123 | 124 | maven-surefire-plugin 125 | 2.22.1 126 | 127 | 128 | maven-jar-plugin 129 | 3.0.2 130 | 131 | 132 | maven-install-plugin 133 | 2.5.2 134 | 135 | 136 | maven-deploy-plugin 137 | 2.8.2 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | org.apache.maven.plugins 146 | maven-assembly-plugin 147 | 3.0.0 148 | 149 | 150 | 151 | jar-with-dependencies 152 | 153 | 154 | NightScoutLoader 155 | false 156 | 157 | 158 | 159 | control.MainNightScoutLoader 160 | 161 | 162 | 163 | 164 | 165 | 166 | package 167 | 168 | single 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | maven-project-info-reports-plugin 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultCellNovoRaw.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import java.text.ParseException; 4 | import java.util.ArrayList; 5 | import java.util.Date; 6 | import utils.CommonUtils; 7 | 8 | public class DBResultCellNovoRaw extends DBResult 9 | { 10 | static final int m_HourlyValues = 25; 11 | static final int m_FinalHourlyValue = 24; 12 | 13 | String m_Date = new String(""); 14 | String m_Type = new String(""); 15 | 16 | String[] m_HourlyValuesPlusTotal = new String[m_HourlyValues]; 17 | 18 | public DBResultCellNovoRaw(String[] rs) 19 | { 20 | if (rs.length == 27) 21 | { 22 | int i = 0; 23 | m_Date = rs[i++]; 24 | m_Type = rs[i++]; 25 | 26 | for (int j = 0; j < m_HourlyValues; j++) 27 | { 28 | m_HourlyValuesPlusTotal[j] = rs[i++]; 29 | } 30 | } 31 | } 32 | 33 | public ArrayList createDBResults() 34 | { 35 | ArrayList result = new ArrayList(); 36 | 37 | // We're not really interested in the final total value 38 | for (int i = 0; i < m_FinalHourlyValue; i++) 39 | { 40 | if (m_Type.equals("Blood Glucose")) 41 | { 42 | ArrayList bgs = this.readBGValues(m_HourlyValuesPlusTotal[i]); 43 | 44 | // How many results do we have? 45 | // Distribute them across the hour evenly. 46 | int minGap = 60 / (bgs.size() > 0 ? bgs.size() : 1); 47 | 48 | int j = 0; 49 | for (Double d : bgs) 50 | { 51 | Date date = createDateFromString(m_Date, i, j++ * minGap); 52 | DBResult dbRes = createDBResult("BG", date, d); 53 | result.add(dbRes); 54 | } 55 | } 56 | else if (m_Type.equals("Food")) 57 | { 58 | if (m_HourlyValuesPlusTotal[i].length() > 0) 59 | { 60 | Date date = createDateFromString(m_Date, i); 61 | DBResult dbRes = createDBResult("Carbs", date, m_HourlyValuesPlusTotal[i]); 62 | result.add(dbRes); 63 | } 64 | } 65 | else if (m_Type.equals("Bolus")) 66 | { 67 | if (m_HourlyValuesPlusTotal[i].length() > 0) 68 | { 69 | Date date = createDateFromString(m_Date, i); 70 | DBResult dbRes = createDBResult("Standard Bolus", date, m_HourlyValuesPlusTotal[i]); 71 | result.add(dbRes); 72 | } 73 | } 74 | } 75 | 76 | return result; 77 | } 78 | 79 | public boolean isValid() 80 | { 81 | boolean result = false; 82 | 83 | if ( (m_Date.length() > 0 && m_Type.length() > 0) && 84 | !m_Date.equals("Date") ) 85 | { 86 | 87 | result = true; 88 | } 89 | 90 | return result; 91 | } 92 | 93 | private DBResult createDBResult(String type, Date date, String val) 94 | { 95 | DBResult result = new DBResult(); 96 | 97 | Double d = readValue(val); 98 | result.setM_Time(date); 99 | result.setM_ResultType(type); 100 | result.setM_Result(Double.toString(d)); 101 | 102 | // Set epoch millies too for later use in comparator 103 | result.setM_EpochMillies(date.getTime()); 104 | 105 | return result; 106 | } 107 | 108 | private DBResult createDBResult(String type, Date date, Double val) 109 | { 110 | DBResult result = new DBResult(); 111 | 112 | result.setM_Time(date); 113 | result.setM_ResultType(type); 114 | result.setM_Result(Double.toString(val)); 115 | 116 | // Set epoch millies too for later use in comparator 117 | result.setM_EpochMillies(date.getTime()); 118 | 119 | return result; 120 | } 121 | 122 | 123 | private Date createDateFromString(String date, int hour) 124 | { 125 | Date result = createDateFromString(date, hour, 0); 126 | return result; 127 | } 128 | 129 | private Date createDateFromString(String date, int hour, int mins) 130 | { 131 | Date result = new Date(0); 132 | 133 | String format = new String("EEEE dd MMM yyyyy HH:mm"); 134 | try 135 | { 136 | String dateTime = date + " " + String.format("%02d", hour) + ":" + String.format("%02d", mins); 137 | 138 | result = CommonUtils.convertDateString(dateTime); 139 | } 140 | catch (ParseException e) 141 | { 142 | // TODO Auto-generated catch block 143 | e.printStackTrace(); 144 | } 145 | 146 | return result; 147 | } 148 | 149 | 150 | private ArrayList readBGValues(String field) 151 | { 152 | ArrayList result = new ArrayList(); 153 | 154 | String[] bgVals = field.split("/ "); 155 | 156 | for (int i = 0; i < bgVals.length; i++) 157 | { 158 | if (bgVals[i].length() > 0) 159 | { 160 | Double val = readValue(bgVals[i]); 161 | result.add(val); 162 | } 163 | } 164 | 165 | return result; 166 | } 167 | 168 | private Double readValue(String val) 169 | { 170 | Double result = 0.0; 171 | 172 | String[] vals = val.split(" "); 173 | 174 | if (vals.length > 0) 175 | { 176 | result = Double.parseDouble(vals[0]); 177 | } 178 | 179 | return result; 180 | } 181 | 182 | /** 183 | * @return the m_Date 184 | */ 185 | public synchronized String getM_Date() { 186 | return m_Date; 187 | } 188 | 189 | /** 190 | * @param m_Date the m_Date to set 191 | */ 192 | public synchronized void setM_Date(String m_Date) { 193 | this.m_Date = m_Date; 194 | } 195 | 196 | /** 197 | * @return the m_Type 198 | */ 199 | public synchronized String getM_Type() { 200 | return m_Type; 201 | } 202 | 203 | /** 204 | * @param m_Type the m_Type to set 205 | */ 206 | public synchronized void setM_Type(String m_Type) { 207 | this.m_Type = m_Type; 208 | } 209 | 210 | /** 211 | * @return the m_HourlyValuesPlusTotal 212 | */ 213 | public synchronized String[] getM_HourlyValuesPlusTotal() { 214 | return m_HourlyValuesPlusTotal; 215 | } 216 | 217 | /** 218 | * @param m_HourlyValuesPlusTotal the m_HourlyValuesPlusTotal to set 219 | */ 220 | public synchronized void setM_HourlyValuesPlusTotal(String[] m_HourlyValuesPlusTotal) { 221 | this.m_HourlyValuesPlusTotal = m_HourlyValuesPlusTotal; 222 | } 223 | 224 | 225 | 226 | 227 | 228 | 229 | } 230 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultMedtronicOld.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import java.util.Date; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | import control.MyLogger; 7 | 8 | public class DBResultMedtronicOld extends DBResultMedtronic 9 | { 10 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 11 | 12 | private static final String m_DateFormat = "dd/MM/yy"; 13 | private static final String m_TimeFormat = "dd/MM/yy H:m:s"; 14 | 15 | static protected String m_ReportRange = "Report Range"; 16 | 17 | /* private boolean m_Valid; 18 | private boolean m_ReportDateRange; 19 | private Date m_StartDate; 20 | private Date m_EndDate; 21 | */ 22 | 23 | static private String[] m_FieldNames = 24 | { 25 | "Index", 26 | "Date", 27 | "Time", 28 | "Timestamp", 29 | "New Device Time", 30 | "BG Reading (mmol/L)", 31 | "Linked BG Meter ID", 32 | "Temp Basal Amount (U/h)", 33 | "Temp Basal Type", 34 | "Temp Basal Duration (hh:mm:ss)", 35 | "Bolus Type", 36 | "Bolus Volume Selected (U)", 37 | "Bolus Volume Delivered (U)", 38 | "Bolus Duration (hh:mm:ss)", 39 | "Prime Type", 40 | "Prime Volume Delivered (U)", 41 | "Suspend", 42 | "Rewind", 43 | "BWZ Estimate (U)", 44 | "BWZ Target High BG (mmol/L)", 45 | "BWZ Target Low BG (mmol/L)", 46 | "BWZ Carb Ratio (grams)", 47 | "BWZ Insulin Sensitivity (mmol/L)", 48 | "BWZ Carb Input (grams)", 49 | "BWZ BG Input (mmol/L)", 50 | "BWZ Correction Estimate (U)", 51 | "BWZ Food Estimate (U)", 52 | "BWZ Active Insulin (U)", 53 | "Alarm", 54 | "Sensor Calibration BG (mmol/L)", 55 | "Sensor Glucose (mmol/L)", 56 | "ISIG Value", 57 | "Daily Insulin Total (U)", 58 | "Raw-Type", 59 | "Raw-Values", 60 | "Raw-ID", 61 | "Raw-Upload ID", 62 | "Raw-Seq Num", 63 | "Raw-Device Type", 64 | }; 65 | 66 | static private boolean m_indexesInitialized = false; 67 | static private int m_DateIndex = 0; 68 | static private int m_TimeIndex = 0; 69 | static private int m_BolusTypeIndex = 0; 70 | static private int m_BGIndex = 0; 71 | static private int m_TempBasalAmountIndex = 0; 72 | static private int m_TempBasalDurationIndex = 0; 73 | static private int m_CarbAmountIndex = 0; 74 | static private int m_StandardBolusIndex = 0; 75 | static private int m_BolusDurationIndex = 0; 76 | static private int m_PrimeIndex = 0; 77 | 78 | @Override 79 | public boolean isValid() 80 | { 81 | return m_Valid; 82 | } 83 | 84 | @Override 85 | public boolean isReportRange() 86 | { 87 | return m_ReportDateRange; 88 | } 89 | 90 | public Date getStartReportRange() 91 | { 92 | return m_StartDate; 93 | } 94 | public Date getEndReportRange() 95 | { 96 | return m_EndDate; 97 | } 98 | 99 | public DBResultMedtronicOld(String[] recordSet) 100 | { 101 | super(recordSet); 102 | } 103 | 104 | @Override 105 | protected void initialize() 106 | { 107 | m_StartDate = new Date(0); 108 | m_EndDate = new Date(0); 109 | 110 | m_Valid = true; 111 | m_ReportDateRange = false; 112 | 113 | m_RecordSet = new String[m_FieldNames.length]; 114 | 115 | // Set values in underdlying ResultFromDB from record set 116 | if (m_indexesInitialized == false) 117 | { 118 | m_DateIndex = fieldLocation("Date"); 119 | m_TimeIndex = fieldLocation("Time"); 120 | m_BolusTypeIndex = fieldLocation("Bolus Type"); 121 | m_BGIndex = fieldLocation("BG Reading (mmol/L)"); 122 | m_TempBasalAmountIndex = fieldLocation("Temp Basal Amount (U/h)"); 123 | m_TempBasalDurationIndex = fieldLocation("Temp Basal Duration (hh:mm:ss)"); 124 | m_CarbAmountIndex = fieldLocation("BWZ Carb Input (grams)"); 125 | m_StandardBolusIndex = fieldLocation("Bolus Volume Delivered (U)"); 126 | m_BolusDurationIndex = fieldLocation("Bolus Duration (hh:mm:ss)"); 127 | // m_Time = fieldLocation("Timestamp"); 128 | m_PrimeIndex = fieldLocation("Prime Type"); 129 | 130 | m_indexesInitialized = true; 131 | } 132 | } 133 | 134 | @Override 135 | protected void getDateRangeFromRecordSet(String[] recordSet) 136 | { 137 | // Example: 138 | // Peiro JoanCarles 09/03/2019 00:00 31/05/2019 23:59 Serial Number NG1623501H 139 | // So 3rd field is blank 140 | // 6th says serial number 141 | if (recordSet.length > 1) 142 | { 143 | m_Logger.log(Level.FINE, "DBResultMedtronic Comparing:<" + recordSet[0] + "> and <" + m_ReportRange + ">"); 144 | if (recordSet[0].equals(m_ReportRange)) 145 | { 146 | m_ReportDateRange = true; 147 | m_StartDate = parseFileDate(recordSet[1]); 148 | m_EndDate = parseFileDate(recordSet[3]); 149 | } 150 | } 151 | } 152 | 153 | @Override 154 | protected String getDateFormat() 155 | { 156 | return m_DateFormat; 157 | } 158 | 159 | @Override 160 | protected String getTimeFormat() 161 | { 162 | return m_TimeFormat; 163 | } 164 | 165 | 166 | private int fieldLocation(String f) 167 | { 168 | int result = super.fieldLocation(f, m_FieldNames); 169 | return result; 170 | } 171 | 172 | @Override 173 | protected int getDateIndex() 174 | { 175 | return m_DateIndex; 176 | } 177 | 178 | @Override 179 | protected int getTimeIndex() 180 | { 181 | return m_TimeIndex; 182 | } 183 | 184 | @Override 185 | protected int getBolusTypeIndex() 186 | { 187 | return m_BolusTypeIndex; 188 | } 189 | 190 | @Override 191 | protected int getBGIndex() 192 | { 193 | return m_BGIndex; 194 | } 195 | 196 | @Override 197 | protected int getTempBasalAmountIndex() 198 | { 199 | return m_TempBasalAmountIndex; 200 | } 201 | 202 | @Override 203 | protected int getTempBasalDurationIndex() 204 | { 205 | return m_TempBasalDurationIndex; 206 | } 207 | 208 | @Override 209 | protected int getCarbAmountIndex() 210 | { 211 | return m_CarbAmountIndex; 212 | } 213 | 214 | @Override 215 | protected int getStandardBolusIndex() 216 | { 217 | return m_StandardBolusIndex; 218 | } 219 | 220 | @Override 221 | protected int getBolusDurationIndex() 222 | { 223 | return m_BolusDurationIndex; 224 | } 225 | 226 | @Override 227 | protected int getPrimeIndex() 228 | { 229 | return m_PrimeIndex; 230 | } 231 | 232 | } 233 | -------------------------------------------------------------------------------- /src/main/java/analysis/AnalyzerTrendResultEntry.java: -------------------------------------------------------------------------------- 1 | package analysis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | 7 | import analysis.AnalyzerResultEntryInterval.DBResultEntryProfile; 8 | import analysis.AnalyzerResultEntryInterval.DBResultEntryProfileChange; 9 | import analysis.AnalyzerResultEntryInterval.DBResultEntryProfileDirection; 10 | import control.MyLogger; 11 | import utils.CommonUtils; 12 | 13 | public class AnalyzerTrendResultEntry 14 | { 15 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 16 | 17 | private static Integer m_Static_ID = 0; // Assign an ID to each result created. 18 | private int m_ID = 0; // Assign an ID to each result created. 19 | 20 | private ArrayList m_ResultEntryIntervals; 21 | private Boolean m_GoesHypo; 22 | private Boolean m_GoesHyper; 23 | private DBResultEntryProfileChange m_DBResultEntryProfileChange; 24 | private DBResultEntryProfile m_StartProfile; 25 | private DBResultEntryProfile m_EndProfile; 26 | private DBResultEntryProfileDirection m_ProfileDirection; 27 | 28 | private int m_StartHour; 29 | private int m_EndHour; 30 | private int m_Offset; 31 | 32 | AnalyzerTrendResultEntry(boolean goesHypo, boolean goesHyper, 33 | DBResultEntryProfile startProfile, DBResultEntryProfile endProfile, 34 | DBResultEntryProfileDirection profileDirection, 35 | int startHour, int endHour, int offset) 36 | { 37 | m_Static_ID++; 38 | m_ID = m_Static_ID; 39 | 40 | m_Logger.log(Level.FINE, "Just built AnalyzerEntriesCGMDay " + m_ID + " Profile Start: " + 41 | startProfile.toString() + " Profile End: " + 42 | endProfile.toString() + " Start Hour: " + startHour + " End Hour: " + endHour); 43 | 44 | m_ResultEntryIntervals = new ArrayList(); 45 | 46 | m_GoesHypo = goesHypo; 47 | m_GoesHyper = goesHyper; 48 | m_StartProfile = startProfile; 49 | m_EndProfile = endProfile; 50 | m_StartHour = startHour; 51 | m_EndHour = endHour; 52 | m_ProfileDirection = profileDirection; 53 | m_Offset = offset; 54 | } 55 | 56 | AnalyzerTrendResultEntry(DBResultEntryProfileChange profileChange, int startHour, int endHour, int offset) 57 | { 58 | m_Static_ID++; 59 | m_ID = m_Static_ID; 60 | 61 | m_Logger.log(Level.FINE, "Just built AnalyzerEntriesCGMDay " + m_ID + " Profile: " + 62 | profileChange.toString() + " Start Hour: " + startHour + " End Hour: " + endHour); 63 | 64 | m_ResultEntryIntervals = new ArrayList(); 65 | 66 | m_DBResultEntryProfileChange = profileChange; 67 | m_StartHour = startHour; 68 | m_EndHour = endHour; 69 | m_Offset = offset; 70 | } 71 | 72 | public boolean addSingleResultEntry(AnalyzerResultEntryInterval e) 73 | { 74 | boolean result = false; 75 | 76 | boolean profileDirection = e.getM_ProfileDirection() == m_ProfileDirection ? true : false; 77 | /* boolean goesHypo = e.getM_GoesHypo() == m_GoesHypo ? true : false; 78 | boolean goesHyper = e.getM_GoesHyper() == m_GoesHyper ? true : false; 79 | boolean startProfile = e.getM_StartProfile() == m_StartProfile ? true : false; 80 | boolean endProfile = e.getM_EndProfile() == m_EndProfile ? true : false; 81 | 82 | 83 | // We group results with different end profiles together 84 | boolean exactlySameProfile = 85 | (goesHypo == true && goesHyper == true && startProfile == true && 86 | endProfile == true && profileDirection == true) ? true : false;*/ 87 | 88 | boolean sameProfile = (profileDirection == true) ? true : false; 89 | 90 | if ( (sameProfile) && // Same profile 91 | CommonUtils.get24Hour(e.getM_PeriodStart()) >= m_StartHour + m_Offset && // Start time 92 | CommonUtils.get24Hour(e.getM_PeriodEnd()) <= m_EndHour + m_Offset) 93 | { 94 | m_ResultEntryIntervals.add(e); 95 | e.setM_AnalyzerTrendResultEntry(this); 96 | result = true; 97 | } 98 | 99 | return result; 100 | } 101 | 102 | 103 | 104 | public synchronized static void resetStaticID() 105 | { 106 | m_Static_ID = 0; 107 | } 108 | 109 | /** 110 | * @return the m_ID 111 | */ 112 | public synchronized int getM_ID() 113 | { 114 | return m_ID; 115 | } 116 | 117 | /** 118 | * @return the m_ResultEntryIntervals 119 | */ 120 | public synchronized ArrayList getM_ResultEntryIntervals() { 121 | return m_ResultEntryIntervals; 122 | } 123 | 124 | /** 125 | * @return the m_DBResultEntryProfileChange 126 | */ 127 | public synchronized DBResultEntryProfileChange getM_DBResultEntryProfileChange() { 128 | return m_DBResultEntryProfileChange; 129 | } 130 | 131 | /** 132 | * @return the m_StartHour 133 | */ 134 | public synchronized int getM_StartHour() { 135 | return m_StartHour; 136 | } 137 | 138 | /** 139 | * @return the m_EndHour 140 | */ 141 | public synchronized int getM_EndHour() { 142 | return m_EndHour; 143 | } 144 | 145 | /** 146 | * @return the m_Offset 147 | */ 148 | public synchronized int getM_Offset() { 149 | return m_Offset; 150 | } 151 | 152 | /** 153 | * @return the m_GoesHypo 154 | */ 155 | public synchronized Boolean getM_GoesHypo() { 156 | return m_GoesHypo; 157 | } 158 | 159 | /** 160 | * @return the m_GoesHyper 161 | */ 162 | public synchronized Boolean getM_GoesHyper() { 163 | return m_GoesHyper; 164 | } 165 | 166 | /** 167 | * @return the m_StartProfile 168 | */ 169 | public synchronized DBResultEntryProfile getM_StartProfile() { 170 | return m_StartProfile; 171 | } 172 | 173 | /** 174 | * @return the m_EndProfile 175 | */ 176 | public synchronized DBResultEntryProfile getM_EndProfile() { 177 | return m_EndProfile; 178 | } 179 | 180 | /** 181 | * @return the m_ProfileDirection 182 | */ 183 | public synchronized DBResultEntryProfileDirection getM_ProfileDirection() { 184 | return m_ProfileDirection; 185 | } 186 | 187 | /** 188 | * @return the m_ProfileDirection 189 | */ 190 | public synchronized String getM_ProfileDirectionStr(boolean mmol) 191 | { 192 | String result = AnalyzerResultEntryInterval.getProfileDirectionStr(mmol, m_ProfileDirection); 193 | return result; 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /src/main/java/win/WinWhy.java: -------------------------------------------------------------------------------- 1 | package win; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.FlowLayout; 5 | //import java.awt.Graphics; 6 | import java.awt.Image; 7 | 8 | import javax.imageio.ImageIO; 9 | import javax.swing.ImageIcon; 10 | import javax.swing.JButton; 11 | import javax.swing.JDialog; 12 | import javax.swing.JLabel; 13 | import javax.swing.JPanel; 14 | import javax.swing.JScrollPane; 15 | import javax.swing.border.EmptyBorder; 16 | 17 | import control.MainNightScoutLoader; 18 | import control.MyLogger; 19 | 20 | import javax.swing.JTextArea; 21 | import java.awt.event.ActionListener; 22 | import java.awt.image.BufferedImage; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.util.logging.Level; 26 | import java.util.logging.Logger; 27 | import java.awt.event.ActionEvent; 28 | 29 | public class WinWhy extends JDialog 30 | { 31 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 32 | 33 | // THIS IS A DELIBERATE CHANGE 34 | 35 | /** 36 | * 37 | */ 38 | private static final long serialVersionUID = -51832866421758739L; 39 | 40 | private final JPanel contentPanel = new JPanel(); 41 | 42 | // private final ImagePanel imagePanel = new ImagePanel(); 43 | 44 | private String m_WhyText; 45 | 46 | /** 47 | * Create the dialog. 48 | */ 49 | public WinWhy(String title) 50 | { 51 | URL url = MainNightScoutLoader.class.getResource("/Nightscout.jpg"); 52 | ImageIcon img = new ImageIcon(url); 53 | setIconImage(img.getImage()); 54 | 55 | super.setTitle(title); 56 | 57 | m_WhyText = new String(); 58 | 59 | m_WhyText += "NightScoutLoader\r\n\r\nThe reason behind this application:\r\n\r\n"; 60 | m_WhyText += " Dawn was 19 months 21st March 2003 when blue-light rushed from Doctor's surgery to hospital.\r\n"; 61 | m_WhyText += " Since then (as every parent with a T1 child knows) life has never been the same.\r\n"; 62 | m_WhyText += " She was in hospital for 10 straight days, advanced stage ketoacidosis and in a really bad way.\r\n\r\n"; 63 | m_WhyText += " In hindsight, the virus we thought she had was more serious than we realised.\r\n"; 64 | m_WhyText += " \r\n"; 65 | m_WhyText += " She's pictured left on her 2nd Birthday August 2003.\r\n"; 66 | m_WhyText += " \r\n"; 67 | m_WhyText += " Since then Debbie & I did what we could to ensure her health was fine.\r\n"; 68 | m_WhyText += " In the early days, Dawn was on combination insulin injections - twice a day.\r\n"; 69 | m_WhyText += " We soon exhausted all available combinations and within a year were moving to 3 then 4 injections.\r\n"; 70 | m_WhyText += " Realising the importance of data, I immediately got on top of meter downloads and \r\n"; 71 | m_WhyText += " with my technical skills, I established the process of annotating results with what she ate\r\n"; 72 | m_WhyText += " \r\n"; 73 | m_WhyText += " In 2008, Dawn went onto a Medtronic pump for the first time. \r\n"; 74 | m_WhyText += " Leading up to that date, we needed to firmly establish carb counting. \r\n"; 75 | m_WhyText += " Looking around for a mobile device that could help & finding none, I wrote one on Windows Mobile \r\n"; 76 | m_WhyText += " that we used for several years until gaining expertise in carb counting. \r\n"; 77 | m_WhyText += " I developed a PC tool that would link historical food information to the Medtronic Care Link site too. \r\n"; 78 | m_WhyText += " \r\n"; 79 | m_WhyText += " In 2012, Dawn moved to Roche. \r\n"; 80 | m_WhyText += " Later that year, I reverse engineered the Roche SQL Server Database and developed some spreadsheets \r\n"; 81 | m_WhyText += " that could query directly pulling data down into my own tables & graphs.\r\n"; 82 | m_WhyText += " \r\n"; 83 | m_WhyText += " Once I discovered NightScout in 2015, I realised this early Roche work could be of use\r\n"; 84 | m_WhyText += " and so began the project Nightscout Loader in December 2015.\r\n"; 85 | m_WhyText += " \r\n"; 86 | m_WhyText += " Since then, Dawn moved to OmniPod and with only real access to data being through Diasend,\r\n"; 87 | m_WhyText += " I strengthened support for this file type.\r\n"; 88 | m_WhyText += " Most recently, I've added the audit and analytical capabililties. I think they're useful. Hope you do too.\r\n"; 89 | 90 | setBounds(50, 50, 1250, 650); 91 | getContentPane().setLayout(new BorderLayout()); 92 | // getContentPane().setLayout(new FlowLayout()); 93 | 94 | contentPanel.setLayout(new FlowLayout()); 95 | contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); 96 | 97 | 98 | // This code scales the picture but it the app doesn't launch 99 | // when exported 100 | 101 | // Using http://www.mkyong.com/java/how-to-read-an-image-from-file-or-url/ 102 | BufferedImage myPicture = null; 103 | try { 104 | URL url2 = MainNightScoutLoader.class.getResource("/Dawn.JPG"); 105 | myPicture = ImageIO.read(url2); 106 | } catch (IOException e) { 107 | e.printStackTrace(); 108 | m_Logger.log(Level.SEVERE, "<"+this.getClass().getName()+">" + "deeperAnalyseResults: Just caught an exception " + e.getMessage()); 109 | } 110 | 111 | Image dimg = myPicture.getScaledInstance(600, 400, Image.SCALE_SMOOTH); 112 | JLabel picLabel = new JLabel(new ImageIcon(dimg)); 113 | 114 | add(picLabel); 115 | getContentPane().add(picLabel, BorderLayout.WEST); 116 | 117 | 118 | 119 | // getContentPane().add(imagePanel, BorderLayout.NORTH); 120 | 121 | getContentPane().add(contentPanel, BorderLayout.EAST); 122 | { 123 | JTextArea txtrNightscoutloader = new JTextArea(); 124 | txtrNightscoutloader.setText(m_WhyText); 125 | contentPanel.add(txtrNightscoutloader); 126 | 127 | JScrollPane scrollPane = new JScrollPane(txtrNightscoutloader); 128 | getContentPane().add(scrollPane, BorderLayout.CENTER); 129 | } 130 | 131 | 132 | { 133 | JPanel buttonPane = new JPanel(); 134 | buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); 135 | getContentPane().add(buttonPane, BorderLayout.SOUTH); 136 | { 137 | JButton okButton = new JButton("OK"); 138 | okButton.addActionListener(new ActionListener() { 139 | public void actionPerformed(ActionEvent arg0) { 140 | setVisible(false); 141 | } 142 | }); 143 | okButton.setActionCommand("OK"); 144 | buttonPane.add(okButton); 145 | getRootPane().setDefaultButton(okButton); 146 | } 147 | { 148 | JButton cancelButton = new JButton("Cancel"); 149 | cancelButton.addActionListener(new ActionListener() { 150 | public void actionPerformed(ActionEvent arg0) { 151 | setVisible(false); 152 | } 153 | }); 154 | cancelButton.setActionCommand("Cancel"); 155 | buttonPane.add(cancelButton); 156 | } 157 | } 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/loader/DataLoadCellNovo.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.Collections; 9 | import java.util.logging.Level; 10 | import java.util.logging.Logger; 11 | 12 | import control.MyLogger; 13 | import entity.DBResult; 14 | import entity.DBResultCellNovoRaw; 15 | import entity.ResultFromDBComparator; 16 | 17 | public class DataLoadCellNovo extends DataLoadCSVFile 18 | { 19 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 20 | private static final String m_CellNovoSplitBy = ";"; 21 | 22 | 23 | @Override 24 | protected DBResult makeDBResult(String[] res) 25 | { 26 | return null; 27 | } 28 | 29 | @Override 30 | protected ArrayList makeDBResultList(String[] res) 31 | { 32 | ArrayList result = null; 33 | DBResultCellNovoRaw rawRes = new DBResultCellNovoRaw(res); 34 | if (rawRes.isValid()) 35 | { 36 | result = rawRes.createDBResults(); 37 | } 38 | return result; 39 | } 40 | 41 | @Override 42 | protected void orderRawResults() 43 | { 44 | Collections.sort(rawResultsFromDB, new ResultFromDBComparator(false)); 45 | } 46 | 47 | @Override 48 | protected String loadStringName() 49 | { 50 | // TODO Auto-generated method stub 51 | return null; 52 | } 53 | 54 | @Override 55 | protected String getSplitBy() 56 | { 57 | return m_CellNovoSplitBy; 58 | } 59 | 60 | public static boolean isCellNovo(String fileName) 61 | { 62 | boolean result = false; 63 | BufferedReader br = null; 64 | String line = ""; 65 | String cvsSplitBy = m_CellNovoSplitBy; 66 | 67 | // Expected Format 68 | 69 | boolean ln9Date = false; 70 | boolean ln9Hour0 = false; 71 | boolean ln9Hour1 = false; 72 | boolean ln9Hour2 = false; 73 | boolean ln9Hour3 = false; 74 | boolean ln9Hour4 = false; 75 | boolean ln9Hour5 = false; 76 | boolean ln9Hour6 = false; 77 | boolean ln9Hour7 = false; 78 | boolean ln9Hour8 = false; 79 | boolean ln9Hour9 = false; 80 | boolean ln9Hour10 = false; 81 | boolean ln9Hour11 = false; 82 | boolean ln9Hour12 = false; 83 | boolean ln9Hour13 = false; 84 | boolean ln9Hour14 = false; 85 | boolean ln9Hour15 = false; 86 | boolean ln9Hour16 = false; 87 | boolean ln9Hour17 = false; 88 | boolean ln9Hour18 = false; 89 | boolean ln9Hour19 = false; 90 | boolean ln9Hour20 = false; 91 | boolean ln9Hour21 = false; 92 | boolean ln9Hour22 = false; 93 | boolean ln9Hour23 = false; 94 | boolean ln9Total = false; 95 | 96 | 97 | int ln = 0; 98 | int maxLines = 10; 99 | int lineCheck = 9; // Check line 9 as that's where the data really starts 100 | 101 | try 102 | { 103 | br = new BufferedReader(new FileReader(fileName)); 104 | while ((ln <= maxLines) && (line = br.readLine()) != null) 105 | { 106 | ln++; 107 | // use comma as separator 108 | String[] rs = line.split(cvsSplitBy); 109 | 110 | if (ln == lineCheck) 111 | { 112 | int i = 0; 113 | ln9Date = (rs.length > i && rs[i++].equals("Date")) ? true : false; 114 | ln9Hour0 = (rs.length > i && rs[i++].equals("00")) ? true : false; 115 | ln9Hour1 = (rs.length > i && rs[i++].equals("01")) ? true : false; 116 | ln9Hour2 = (rs.length > i && rs[i++].equals("02")) ? true : false; 117 | ln9Hour3 = (rs.length > i && rs[i++].equals("03")) ? true : false; 118 | ln9Hour4 = (rs.length > i && rs[i++].equals("04")) ? true : false; 119 | ln9Hour5 = (rs.length > i && rs[i++].equals("05")) ? true : false; 120 | ln9Hour6 = (rs.length > i && rs[i++].equals("06")) ? true : false; 121 | ln9Hour7 = (rs.length > i && rs[i++].equals("07")) ? true : false; 122 | ln9Hour8 = (rs.length > i && rs[i++].equals("08")) ? true : false; 123 | ln9Hour9 = (rs.length > i && rs[i++].equals("09")) ? true : false; 124 | ln9Hour10 = (rs.length > i && rs[i++].equals("10")) ? true : false; 125 | ln9Hour11 = (rs.length > i && rs[i++].equals("11")) ? true : false; 126 | ln9Hour12 = (rs.length > i && rs[i++].equals("12")) ? true : false; 127 | ln9Hour13 = (rs.length > i && rs[i++].equals("13")) ? true : false; 128 | ln9Hour14 = (rs.length > i && rs[i++].equals("14")) ? true : false; 129 | ln9Hour15 = (rs.length > i && rs[i++].equals("15")) ? true : false; 130 | ln9Hour16 = (rs.length > i && rs[i++].equals("16")) ? true : false; 131 | ln9Hour17 = (rs.length > i && rs[i++].equals("17")) ? true : false; 132 | ln9Hour18 = (rs.length > i && rs[i++].equals("18")) ? true : false; 133 | ln9Hour19 = (rs.length > i && rs[i++].equals("19")) ? true : false; 134 | ln9Hour20 = (rs.length > i && rs[i++].equals("20")) ? true : false; 135 | ln9Hour21 = (rs.length > i && rs[i++].equals("21")) ? true : false; 136 | ln9Hour22 = (rs.length > i && rs[i++].equals("22")) ? true : false; 137 | ln9Hour23 = (rs.length > i && rs[i++].equals("23")) ? true : false; 138 | ln9Total = (rs.length > i && rs[i++].equals("Total"))? true : false; 139 | 140 | } 141 | 142 | } 143 | 144 | result = (ln9Date == true && 145 | ln9Hour0 == true && ln9Hour1 == true && ln9Hour2 == true && ln9Hour3 == true && 146 | ln9Hour4 == true && ln9Hour5 == true && ln9Hour6 == true && ln9Hour7 == true && 147 | ln9Hour8 == true && ln9Hour9 == true && ln9Hour10 == true && ln9Hour11 == true && 148 | ln9Hour12 == true && ln9Hour13 == true && ln9Hour14 == true && ln9Hour15 == true && 149 | ln9Hour16 == true && ln9Hour17 == true && ln9Hour18 == true && ln9Hour19 == true && 150 | ln9Hour20 == true && ln9Hour21 == true && ln9Hour22 == true && ln9Hour23 == true && 151 | ln9Total == true) ? true : false; 152 | 153 | } 154 | catch (FileNotFoundException e) 155 | { 156 | m_Logger.log(Level.SEVERE, "" + "isCellNovo: FileNotFoundException. File " + fileName + " Error " + e.getMessage()); 157 | 158 | e.printStackTrace(); 159 | } 160 | catch (IOException e) 161 | { 162 | m_Logger.log(Level.SEVERE, "" + "isCellNovo: IOException. File " + fileName + " Error " + e.getMessage()); 163 | e.printStackTrace(); 164 | } 165 | finally 166 | { 167 | if (br != null) 168 | { 169 | try 170 | { 171 | br.close(); 172 | } 173 | catch (IOException e) 174 | { 175 | m_Logger.log(Level.SEVERE, "" + "isMedtronic: IOException closing file. File " + fileName + " Error " + e.getMessage()); 176 | e.printStackTrace(); 177 | } 178 | } 179 | } 180 | 181 | return result; 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/entity/DBResultMedtronicNew.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import java.util.Date; 4 | import utils.CommonUtils; 5 | 6 | public class DBResultMedtronicNew extends DBResultMedtronic 7 | { 8 | private static final String m_DateFormat = "yyyy/MM/dd"; 9 | private static final String m_TimeFormat = "yyyy/MM/dd HH:mm:ss"; 10 | 11 | static protected String m_ReportRange = "Serial Number"; 12 | 13 | /* private boolean m_Valid; 14 | private boolean m_ReportDateRange; 15 | private Date m_StartDate; 16 | private Date m_EndDate; 17 | */ 18 | 19 | static private String[] m_FieldNames = 20 | { 21 | "Index", 22 | "Date", 23 | "Time", 24 | "New Device Time", 25 | "BG Reading (mmol/L)", 26 | "Linked BG Meter ID", 27 | "Basal Rate (U/h)", 28 | "Temp Basal Amount", 29 | "Temp Basal Type", 30 | "Temp Basal Duration (h:mm:ss)", 31 | "Bolus Type", 32 | "Bolus Volume Selected (U)", 33 | "Bolus Volume Delivered (U)", 34 | "Bolus Duration (h:mm:ss)", 35 | "Prime Type", 36 | "Prime Volume Delivered (U)", 37 | "Alarm", 38 | "Suspend", 39 | "Rewind", 40 | "BWZ Estimate (U)", 41 | "BWZ Target High BG (mmol/L)", 42 | "BWZ Target Low BG (mmol/L)", 43 | "BWZ Carb Ratio (g/U)", 44 | "BWZ Insulin Sensitivity (mg/dL/U)", 45 | "BWZ Carb Input (grams)", 46 | "BWZ BG Input (mmol/L)", 47 | "BWZ Correction Estimate (U)", 48 | "BWZ Food Estimate (U)", 49 | "BWZ Active Insulin (U)", 50 | "Sensor Calibration BG (mmol/L)", 51 | "Sensor Glucose (mmol/L)", 52 | "ISIG Value", 53 | "Event Marker", 54 | "Bolus Number", 55 | "Bolus Cancellation Reason", 56 | "BWZ Unabsorbed Insulin Total (U)", 57 | "Final Bolus Estimate", 58 | "Scroll Step Size", 59 | "Insulin Action Curve Time", 60 | "Sensor Calibration Rejected Reason", 61 | "Preset Bolus", 62 | "Bolus Source", 63 | "Network Device Associated Reason", 64 | "Network Device Disassociated Reason", 65 | "Network Device Disconnected Reason", 66 | "Sensor Exception", 67 | "Preset Temp Basal Name", 68 | }; 69 | 70 | static private boolean m_indexesInitialized = false; 71 | static private int m_DateIndex = 0; 72 | static private int m_TimeIndex = 0; 73 | static private int m_BolusTypeIndex = 0; 74 | static private int m_BGIndex = 0; 75 | static private int m_TempBasalAmountIndex = 0; 76 | static private int m_TempBasalDurationIndex = 0; 77 | static private int m_CarbAmountIndex = 0; 78 | static private int m_StandardBolusIndex = 0; 79 | static private int m_BolusDurationIndex = 0; 80 | static private int m_PrimeIndex = 0; 81 | 82 | @Override 83 | public boolean isValid() 84 | { 85 | return m_Valid; 86 | } 87 | 88 | @Override 89 | public boolean isReportRange() 90 | { 91 | return m_ReportDateRange; 92 | } 93 | 94 | public Date getStartReportRange() 95 | { 96 | return m_StartDate; 97 | } 98 | public Date getEndReportRange() 99 | { 100 | return m_EndDate; 101 | } 102 | 103 | public DBResultMedtronicNew(String[] recordSet) 104 | { 105 | super(recordSet); 106 | } 107 | 108 | @Override 109 | protected void initialize() 110 | { 111 | m_StartDate = new Date(0); 112 | m_EndDate = new Date(0); 113 | 114 | m_Valid = true; 115 | m_ReportDateRange = false; 116 | 117 | m_RecordSet = new String[m_FieldNames.length]; 118 | 119 | // Set values in underdlying ResultFromDB from record set 120 | if (m_indexesInitialized == false) 121 | { 122 | m_DateIndex = fieldLocation("Date"); 123 | m_TimeIndex = fieldLocation("Time"); 124 | m_BolusTypeIndex = fieldLocation("Bolus Type"); 125 | m_BGIndex = fieldLocation("BG Reading (mmol/L)"); 126 | m_TempBasalAmountIndex = fieldLocation("Temp Basal Amount"); 127 | m_TempBasalDurationIndex = fieldLocation("Temp Basal Duration (h:mm:ss)"); 128 | m_CarbAmountIndex = fieldLocation("BWZ Carb Input (grams)"); 129 | m_StandardBolusIndex = fieldLocation("Bolus Volume Delivered (U)"); 130 | m_BolusDurationIndex = fieldLocation("Bolus Duration (h:mm:ss)"); 131 | // m_Time = fieldLocation("Timestamp"); 132 | m_PrimeIndex = fieldLocation("Prime Type"); 133 | 134 | m_indexesInitialized = true; 135 | } 136 | } 137 | 138 | @Override 139 | protected void getDateRangeFromRecordSet(String[] recordSet) 140 | { 141 | // Example: 142 | // Peiro JoanCarles 09/03/2019 00:00 31/05/2019 23:59 Serial Number NG1623501H 143 | // So 3rd field is blank 144 | // 6th says serial number 145 | if (recordSet.length > 6) 146 | { 147 | if (CommonUtils.stripDoubleQuotes(recordSet[2]).isEmpty() && 148 | CommonUtils.stripDoubleQuotes(recordSet[5]).equals(m_ReportRange)) 149 | { 150 | m_ReportDateRange = true; 151 | 152 | // All fields in this record have double quotes around them 153 | String field3 = getDateFromLine2DateField(CommonUtils.stripDoubleQuotes(recordSet[3])); 154 | String field4 = getDateFromLine2DateField(CommonUtils.stripDoubleQuotes(recordSet[4])); 155 | 156 | m_StartDate = parseFileDate(field3); 157 | m_EndDate = parseFileDate(field4); 158 | } 159 | } 160 | 161 | } 162 | 163 | @Override 164 | protected String getDateFormat() 165 | { 166 | return m_DateFormat; 167 | } 168 | 169 | @Override 170 | protected String getTimeFormat() 171 | { 172 | return m_TimeFormat; 173 | } 174 | 175 | 176 | private String getDateFromLine2DateField(String val) 177 | { 178 | String result = ""; 179 | 180 | // Split by space to lose time... not interested 181 | String[] tokens = val.split(" "); 182 | if (tokens.length > 0) 183 | { 184 | result = tokens[0]; 185 | 186 | // Add a leading zero for those lazy dates 187 | if (result.length() == 7) 188 | { 189 | result = "0" + result; 190 | } 191 | } 192 | 193 | return result; 194 | } 195 | 196 | private int fieldLocation(String f) 197 | { 198 | int result = super.fieldLocation(f, m_FieldNames); 199 | return result; 200 | } 201 | 202 | @Override 203 | protected int getDateIndex() 204 | { 205 | return m_DateIndex; 206 | } 207 | 208 | @Override 209 | protected int getTimeIndex() 210 | { 211 | return m_TimeIndex; 212 | } 213 | 214 | @Override 215 | protected int getBolusTypeIndex() 216 | { 217 | return m_BolusTypeIndex; 218 | } 219 | 220 | @Override 221 | protected int getBGIndex() 222 | { 223 | return m_BGIndex; 224 | } 225 | 226 | @Override 227 | protected int getTempBasalAmountIndex() 228 | { 229 | return m_TempBasalAmountIndex; 230 | } 231 | 232 | @Override 233 | protected int getTempBasalDurationIndex() 234 | { 235 | return m_TempBasalDurationIndex; 236 | } 237 | 238 | @Override 239 | protected int getCarbAmountIndex() 240 | { 241 | return m_CarbAmountIndex; 242 | } 243 | 244 | @Override 245 | protected int getStandardBolusIndex() 246 | { 247 | return m_StandardBolusIndex; 248 | } 249 | 250 | @Override 251 | protected int getBolusDurationIndex() 252 | { 253 | return m_BolusDurationIndex; 254 | } 255 | 256 | @Override 257 | protected int getPrimeIndex() 258 | { 259 | return m_PrimeIndex; 260 | } 261 | 262 | } 263 | -------------------------------------------------------------------------------- /src/test/java/loader/BaseTestTreatment.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.net.URISyntaxException; 6 | import java.net.URL; 7 | import java.net.UnknownHostException; 8 | import java.sql.SQLException; 9 | import java.text.ParseException; 10 | import java.text.SimpleDateFormat; 11 | import java.util.ArrayList; 12 | import java.util.Date; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import java.util.Set; 16 | 17 | import org.junit.jupiter.api.Assertions; 18 | import org.junit.runner.RunWith; 19 | import org.mockito.junit.MockitoJUnitRunner; 20 | import control.MyLogger; 21 | import control.PrefsNightScoutLoader; 22 | import entity.DBResult; 23 | import entity.DBResultEntry; 24 | 25 | @RunWith(MockitoJUnitRunner.class) 26 | public abstract class BaseTestTreatment { 27 | 28 | protected static Double DOUBLE_THRESHOLD = 0.001; 29 | 30 | public BaseTestTreatment() { 31 | try { 32 | MyLogger.setup(true); 33 | } catch (IOException e) { 34 | // TODO Auto-generated catch block 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | protected abstract Object[][] getExpectedTestResults(); 40 | protected abstract String getResourceFileName(); 41 | protected abstract DataLoadFile getDataLoadFile(); 42 | protected abstract SimpleDateFormat getSimpleDateFormat(); 43 | protected abstract String getDateFormat(); 44 | 45 | public ArrayList getDBResultArrayList() 46 | { 47 | return getDataLoadFile().getResultTreatments(); 48 | } 49 | 50 | public ArrayList getDBResultEntryArrayList() 51 | { 52 | return getDataLoadFile().getRawEntryResultsFromDB(); 53 | } 54 | 55 | public void performTestLoad() 56 | { 57 | doDataLoad(); 58 | DataLoadFile dataLoadDiasend = getDataLoadFile(); 59 | Assertions.assertTrue(dataLoadDiasend != null); 60 | try { 61 | assertionTests(dataLoadDiasend); 62 | } catch (ParseException e) { 63 | // TODO Auto-generated catch block 64 | e.printStackTrace(); 65 | } 66 | } 67 | 68 | public void doDataLoad() 69 | { 70 | // This disables any MongoDB connection attempts 71 | PrefsNightScoutLoader.getInstance().setM_NightscoutMongoServer(""); 72 | 73 | // Disable inferring any temp basals 74 | PrefsNightScoutLoader.getInstance().setM_InferTempBasals(false); 75 | 76 | 77 | URL url = this.getClass().getClassLoader().getResource(getResourceFileName()); 78 | Assertions.assertTrue(url != null); 79 | DataLoadFile dataLoadDiasend = getDataLoadFile(); 80 | try { 81 | dataLoadDiasend.initialize(new File(url.toURI()).getAbsolutePath()); 82 | dataLoadDiasend.loadDBResults(); 83 | } catch (URISyntaxException e) { 84 | Assertions.assertTrue(false, e.toString()); 85 | } catch (UnknownHostException e) { 86 | Assertions.assertTrue(false, e.toString()); 87 | } catch (ClassNotFoundException e) { 88 | Assertions.assertTrue(false, e.toString()); 89 | } catch (SQLException e) { 90 | Assertions.assertTrue(false, e.toString()); 91 | } catch (IOException e) { 92 | Assertions.assertTrue(false, e.toString()); 93 | } 94 | 95 | } 96 | 97 | public int countDataLoadEntries(Boolean withBG) 98 | { 99 | int result = 0; 100 | 101 | // Iterate over the HashMap since exact duplicate results at same time 102 | // are filtered out. 103 | 104 | DataLoadFile dataLoadDiasend = getDataLoadFile(); 105 | HashMap map = dataLoadDiasend.getResultTreatmentHashMap(); 106 | Set> entrySet = map.entrySet(); 107 | 108 | for(Map.Entry entry : entrySet) 109 | { 110 | DBResult res = entry.getValue(); 111 | result += res.getM_CP_Glucose() == null 112 | ? withBG == false ? 1 : 0 113 | : withBG == true ? 1 : 0; 114 | } 115 | 116 | return result; 117 | } 118 | 119 | @SuppressWarnings("unused") 120 | public int countExpectedResults() 121 | { 122 | int result = 0; 123 | 124 | for (int c = 0; c < getExpectedTestResults().length; c++) 125 | { 126 | Object[] treatmentObject = getExpectedTestResults()[c]; 127 | int i = 0; 128 | 129 | String dateString = (String) treatmentObject[i++]; 130 | Double bgDouble = (Double)treatmentObject[i++]; 131 | Double insDouble = (Double)treatmentObject[i++]; 132 | Double carbDouble = (Double)treatmentObject[i++]; 133 | String dupeString = (String)treatmentObject[i++]; 134 | 135 | result += dupeString.equals("NO") ? 1 : 0; 136 | } 137 | 138 | return result; 139 | } 140 | 141 | private void assertionTests(DataLoadFile dataLoadDiasend) throws ParseException 142 | { 143 | Assertions.assertTrue(dataLoadDiasend != null); 144 | 145 | for (int c = 0; c < getExpectedTestResults().length; c++) 146 | { 147 | Object[] treatmentObject = getExpectedTestResults()[c]; 148 | int i = 0; 149 | 150 | 151 | // Integer indexInteger = (Integer) treatmentObject[i++]; 152 | String dateString = (String) treatmentObject[i++]; 153 | Double bgDouble = (Double)treatmentObject[i++]; 154 | Double insDouble = (Double)treatmentObject[i++]; 155 | Double carbDouble = (Double)treatmentObject[i++]; 156 | String dupeString = (String)treatmentObject[i++]; 157 | 158 | 159 | Date date = getSimpleDateFormat().parse(dateString); 160 | DBResult result = dataLoadDiasend.getResultTreatmentHashMap().get(date.getTime()); 161 | // DBResult result = dataLoadDiasend.getResultTreatmentHashMap().get(ldtEpoch * 1000); 162 | if (result != null) 163 | { 164 | String messgString = " for Entry " + c + " Date " + dateString + " Treatment Id: " + result.getId(); 165 | Assertions.assertTrue(result != null); 166 | 167 | if (dupeString.equals("NO")) 168 | { 169 | if (bgDouble.equals(0.0)) Assertions.assertTrue(result.getM_CP_Glucose() == null, "BG Differs (not null)" + messgString); 170 | else assertEquals(result.getM_CP_Glucose(), bgDouble, "BG Differs" + messgString); 171 | } 172 | 173 | if (insDouble.equals(0.0)) Assertions.assertTrue(result.getM_CP_Insulin() == null, "Insulin Differs (not null)" + messgString); 174 | else assertEquals(result.getM_CP_Insulin(), insDouble, "Insulin Differs" + messgString); 175 | 176 | if (carbDouble.equals(0.0)) Assertions.assertTrue(result.getM_CP_Carbs() == null, "Carbs Differs (not null)" + messgString); 177 | else assertEquals(result.getM_CP_Carbs(), carbDouble, "Carbs Differs" + messgString); 178 | 179 | } 180 | 181 | else { 182 | Boolean mergedBoolean = dupeString.equals("YES"); 183 | 184 | // System.out.println( 185 | // (mergedBoolean ? "As expected, " : "As NOT expected, ") 186 | // + "unable to find " 187 | // + " Date: " + dateString 188 | // + " BG: " + bgDouble 189 | // + " Ins: " + insDouble 190 | // + " Carbs: " + carbDouble 191 | // + " Dupe: " + dupeString); 192 | 193 | // Only allow dupes to be not found 194 | Assertions.assertTrue(mergedBoolean); 195 | } 196 | } 197 | 198 | } 199 | 200 | private void assertEquals(Double dbl1, Double dbl2, String messageString) 201 | { 202 | Assertions.assertTrue(Math.abs(dbl1 - dbl2) < DOUBLE_THRESHOLD, messageString); 203 | } 204 | 205 | } 206 | -------------------------------------------------------------------------------- /src/main/java/control/ThreadAnalyzer.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.util.ArrayList; 4 | import java.util.logging.Level; 5 | import java.util.logging.Logger; 6 | 7 | import analysis.Analyzer; 8 | import entity.DBResult; 9 | import entity.DBResultEntry; 10 | import win.WinTextWin; 11 | 12 | 13 | public class ThreadAnalyzer implements Runnable 14 | { 15 | private static final Logger m_Logger = Logger.getLogger( MyLogger.class.getName() ); 16 | 17 | // Separate thread for Analyzer to run 18 | private Thread m_AnalyzerThread; 19 | 20 | private String m_ExcelFilename = new String(""); 21 | private WinTextWin m_AutotunerWin = null; 22 | private ArrayList m_DBResultList = null; 23 | 24 | // Analyzer used by thread 25 | private Analyzer m_Analyzer; 26 | 27 | private Boolean m_AnalyzerRunning; 28 | // static Object m_Lock = new Object(); 29 | private Object m_Lock; 30 | 31 | // Thread Synchronization 32 | public void waitUntilFree() 33 | { 34 | synchronized(m_Lock) 35 | { 36 | while (m_AnalyzerRunning) 37 | { 38 | try 39 | { 40 | m_Logger.log( Level.FINE, "ThreadAnalyzer Wait - Running & about to try lock: " + this ); 41 | m_Lock.wait(); 42 | m_Logger.log( Level.FINE, "ThreadAnalyzer Wait - Running & notified : " + this ); 43 | } 44 | catch (InterruptedException e) 45 | { 46 | m_Logger.log(Level.SEVERE, "<"+this.getClass().getName()+">" + "ThreadAnalyzer Wait - EXCEPTION CAUGHT.", e); 47 | } 48 | } 49 | m_Logger.log( Level.FINE, "ThreadAnalyzer Wait - No longer running: " + this); 50 | } 51 | } 52 | // Handler to notify when analyzer completes 53 | AnalyzerCompleteHander m_CompleteHandler; 54 | 55 | // Thread Handler for resynchronization 56 | public static abstract class AnalyzerCompleteHander 57 | { 58 | private Object m_Object; 59 | public AnalyzerCompleteHander(Object obj) 60 | { 61 | m_Object = obj; 62 | } 63 | public abstract void analyzeResultsComplete(Object obj); 64 | public abstract void exceptionRaised(String message); 65 | 66 | public Object getM_Object() 67 | { 68 | return m_Object; 69 | } 70 | } 71 | 72 | public ThreadAnalyzer(Analyzer analyzer) 73 | { 74 | m_AnalyzerRunning = true; // Initialise the thread in running state 75 | m_AnalyzerThread = new Thread(this); 76 | m_Analyzer = analyzer; 77 | m_CompleteHandler = null; 78 | 79 | // Thread synchronization 80 | m_Lock = new Object(); 81 | } 82 | 83 | public ThreadAnalyzer(ArrayList results, ArrayList resultEntries) 84 | { 85 | m_AnalyzerRunning = true; // Initialise the thread in running state 86 | m_AnalyzerThread = new Thread(this); 87 | m_Analyzer = new Analyzer(results, resultEntries); 88 | m_CompleteHandler = null; 89 | 90 | // Thread synchronization 91 | m_Lock = new Object(); 92 | } 93 | 94 | public ThreadAnalyzer(ArrayList results, ArrayList resultEntries, boolean summaryOnly) 95 | { 96 | m_AnalyzerRunning = true; // Initialise the thread in running state 97 | m_AnalyzerThread = new Thread(this); 98 | m_Analyzer = new Analyzer(results, resultEntries, summaryOnly); 99 | m_CompleteHandler = null; 100 | 101 | // Thread synchronization 102 | m_Lock = new Object(); 103 | } 104 | 105 | public ThreadAnalyzer(ArrayList results, ArrayList resultEntries, Analyzer.AnalyzerMode mode) 106 | { 107 | m_AnalyzerRunning = true; // Initialise the thread in running state 108 | m_AnalyzerThread = new Thread(this); 109 | m_Analyzer = new Analyzer(results, resultEntries, mode); 110 | m_CompleteHandler = null; 111 | 112 | // Thread synchronization 113 | m_Lock = new Object(); 114 | } 115 | 116 | public void analyzeResults(AnalyzerCompleteHander completeHandler) 117 | { 118 | m_CompleteHandler = completeHandler; 119 | m_AnalyzerThread.start(); 120 | } 121 | 122 | public void run() 123 | { 124 | m_AnalyzerRunning = true; 125 | synchronized(m_Lock) 126 | { 127 | // Launch the analyze method 128 | 129 | // Analyzer.AnalyzerResult analyzerResult = m_Analyzer.analyzeResults(m_DBResultList, m_ExcelFilename); 130 | Analyzer.AnalyzerResult analyzerResult = m_Analyzer.analyzeResults(m_DBResultList, m_ExcelFilename, m_AutotunerWin); 131 | m_Logger.log(Level.FINE, "analyzeResults(m_DBResultList, m_ExcelFilename) returned: " + analyzerResult); 132 | 133 | if (analyzerResult == Analyzer.AnalyzerResult.analysisComplete) 134 | { 135 | m_CompleteHandler.analyzeResultsComplete(m_CompleteHandler.getM_Object()); 136 | } 137 | else if (analyzerResult == Analyzer.AnalyzerResult.datesAreReversed) 138 | { 139 | m_Logger.log(Level.FINE, "Raising exception now"); 140 | m_CompleteHandler.exceptionRaised("Analysis did not run since start and end dates are reversed. Please check and try again."); 141 | } 142 | else if (analyzerResult == Analyzer.AnalyzerResult.noDataToAnalyze) 143 | { 144 | m_Logger.log(Level.FINE, "Raising exception now"); 145 | m_CompleteHandler.exceptionRaised("There are no results to analyze"); 146 | } 147 | 148 | m_AnalyzerRunning = false; 149 | m_Lock.notifyAll(); 150 | 151 | // Kill the thread 152 | m_AnalyzerThread.interrupt(); 153 | } 154 | } 155 | 156 | /** 157 | * @return the m_ExcelFilename 158 | */ 159 | public synchronized String getM_ExcelFilename() { 160 | return m_ExcelFilename; 161 | } 162 | 163 | /** 164 | * @param m_ExcelFilename the m_ExcelFilename to set 165 | */ 166 | public synchronized void setM_ExcelFilename(String m_ExcelFilename) { 167 | this.m_ExcelFilename = m_ExcelFilename; 168 | } 169 | 170 | /** 171 | * @return the m_AutotunerWin 172 | */ 173 | public synchronized WinTextWin getM_AutotunerWin() { 174 | return m_AutotunerWin; 175 | } 176 | 177 | /** 178 | * @param m_AutotunerWin the m_AutotunerWin to set 179 | */ 180 | public synchronized void setM_AutotunerWin(WinTextWin m_AutotunerWin) { 181 | this.m_AutotunerWin = m_AutotunerWin; 182 | } 183 | 184 | /** 185 | * @return the m_DBResultList 186 | */ 187 | public synchronized ArrayList getM_DBResultList() { 188 | return m_DBResultList; 189 | } 190 | 191 | /** 192 | * @param m_DBResultList the m_DBResultList to set 193 | */ 194 | public synchronized void setM_DBResultList(ArrayList m_DBResultList) { 195 | this.m_DBResultList = m_DBResultList; 196 | } 197 | 198 | /** 199 | * @return the m_Analyzer 200 | */ 201 | public synchronized Analyzer getM_Analyzer() { 202 | return m_Analyzer; 203 | } 204 | 205 | /** 206 | * @param m_Analyzer the m_Analyzer to set 207 | */ 208 | public synchronized void setM_Analyzer(Analyzer m_Analyzer) { 209 | this.m_Analyzer = m_Analyzer; 210 | } 211 | 212 | /** 213 | * @return the m_AnalyzerRunning 214 | */ 215 | public synchronized Boolean getM_AnalyzerRunning() { 216 | return m_AnalyzerRunning; 217 | } 218 | 219 | /** 220 | * @param m_AnalyzerRunning the m_AnalyzerRunning to set 221 | */ 222 | public synchronized void setM_AnalyzerRunning(Boolean m_AnalyzerRunning) { 223 | this.m_AnalyzerRunning = m_AnalyzerRunning; 224 | } 225 | 226 | 227 | } 228 | -------------------------------------------------------------------------------- /src/main/java/control/ThreadMongoDBAlerter.java: -------------------------------------------------------------------------------- 1 | package control; 2 | 3 | import java.io.IOException; 4 | import java.util.Date; 5 | //import java.sql.SQLException; 6 | import java.text.ParseException; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | import loader.DataLoadBase; 11 | import loader.DataLoadNightScoutTreatments; 12 | 13 | // Purpose of this class is to alert the application on any updates to the underlying 14 | // MongoDB 15 | // Abstract class since there are two primary intended uses - one on treatments one on sensor results 16 | public abstract class ThreadMongoDBAlerter implements Runnable 17 | { 18 | private static final Logger m_Logger = Logger.getLogger( MyLogger.class.getName() ); 19 | 20 | // Separate thread for data loads 21 | private Thread m_LoadThread; 22 | 23 | /** 24 | * @return the m_LoadThread 25 | */ 26 | public synchronized Thread getM_LoadThread() { 27 | return m_LoadThread; 28 | } 29 | 30 | /** 31 | * @param m_LoadThread the m_LoadThread to set 32 | */ 33 | public synchronized void setM_LoadThread(Thread m_LoadThread) { 34 | this.m_LoadThread = m_LoadThread; 35 | } 36 | 37 | // Data Loader used by thread 38 | protected DataLoadNightScoutTreatments m_DataLoader; 39 | protected Date m_LastResultAt; 40 | protected Date m_CurrentResultAt; 41 | protected String m_CurrentResultBy; 42 | 43 | private Boolean m_LoadRunning; 44 | private Object m_Lock; 45 | 46 | private Boolean m_FirstCheckComplete; 47 | 48 | private int m_SleepInterval; 49 | 50 | 51 | // Abstract mmethod that must be overridden 52 | protected abstract void checkDBForUpdates() throws IOException, ParseException; 53 | 54 | protected abstract String whatIsChecked(); 55 | 56 | protected void compareAndNotify() 57 | { 58 | final Date epoch = new Date(0); 59 | 60 | m_Logger.log(Level.FINE, "Thread check on " + whatIsChecked() + " on MongoDB. Most recent date/time " 61 | + m_CurrentResultAt.toString() + " by '" + m_CurrentResultBy + "'"); 62 | 63 | if (!m_CurrentResultAt.equals(epoch) && m_CurrentResultAt.after(m_LastResultAt)) 64 | { 65 | // Check if this is the first change detected 66 | // Could be start up or a delete 67 | if (m_FirstCheckComplete == true) 68 | { 69 | // Something has changed, generate an info message 70 | m_Logger.log(Level.INFO, "Update detected to " + whatIsChecked() + " on MongoDB. Update at " 71 | + m_CurrentResultAt.toString() + " by '" + m_CurrentResultBy + "'"); 72 | } 73 | m_FirstCheckComplete = true; 74 | } 75 | m_LastResultAt = m_CurrentResultAt; 76 | // Reset "by" 77 | m_CurrentResultBy = ""; 78 | } 79 | 80 | // Thread Synchronization 81 | public void waitUntilFree() 82 | { 83 | synchronized(m_Lock) 84 | { 85 | while (m_LoadRunning) 86 | { 87 | try 88 | { 89 | m_Logger.log( Level.FINE, "ThreadDataLoad Wait - Running & about to try lock: " + this ); 90 | m_Lock.wait(); 91 | m_Logger.log( Level.FINE, "ThreadDataLoad Wait - Running & notified : " + this ); 92 | } 93 | catch (InterruptedException e) 94 | { 95 | m_Logger.log(Level.SEVERE, "<"+this.getClass().getName()+">" + "ThreadDataLoad Wait - EXCEPTION CAUGHT.", e); 96 | } 97 | } 98 | m_Logger.log( Level.FINE, "ThreadDataLoad Wait - No longer running: " + this); 99 | } 100 | } 101 | // Handler to notify when load completes 102 | DataLoadCompleteHander m_CompleteHandler; 103 | 104 | // Thread Handler for resynchronization 105 | public static abstract class DataLoadCompleteHander 106 | { 107 | private Object m_Object; 108 | public DataLoadCompleteHander(Object obj) 109 | { 110 | m_Object = obj; 111 | } 112 | public abstract void dataLoadComplete(Object obj); 113 | public abstract void exceptionRaised(String message); 114 | 115 | public Object getM_Object() 116 | { 117 | return m_Object; 118 | } 119 | } 120 | 121 | public ThreadMongoDBAlerter() 122 | { 123 | m_LoadRunning = true; // Initialise the thread in running state 124 | m_LoadThread = new Thread(this); 125 | m_DataLoader = new DataLoadNightScoutTreatments(); 126 | m_LastResultAt = new Date(0); // Initialized to epoch time 127 | m_CurrentResultAt = new Date(0); // Initialized to epoch time 128 | m_CurrentResultBy = new String(); 129 | 130 | m_CompleteHandler = null; 131 | 132 | // Thread synchronization 133 | m_Lock = new Object(); 134 | 135 | m_FirstCheckComplete = false; // Initialize to false until first check 136 | 137 | // Set for 10 minutes by default but now from preferences 138 | // m_SleepInterval = 60 * 10; 139 | m_SleepInterval = PrefsNightScoutLoader.getInstance().getM_MongoDBAlerterCheckInterval() * 60 * 10; 140 | } 141 | 142 | public void interrupThread() 143 | { 144 | m_LoadThread.interrupt(); 145 | } 146 | 147 | public void startThread() 148 | { 149 | // m_CompleteHandler = completeHandler; 150 | 151 | m_LoadThread.start(); 152 | } 153 | 154 | public void run() 155 | { 156 | m_LoadRunning = true; 157 | synchronized(m_Lock) 158 | { 159 | try 160 | { 161 | // Now if preference is set to 0 in options and then changed, it will have no effect 162 | // the thread is effectively dead and never re-created. THis is fine. Expect user to 163 | // relaunch application to reenable alerting 164 | // Similarly, if value is changed, change only takes effect on next launch 165 | if (m_SleepInterval > 0) 166 | { 167 | // Go into an endless loop, checking for updates then sleeping in between 168 | while (!Thread.interrupted()) 169 | { 170 | // Call MongoDB looking for any updates. 171 | // Then block 172 | // 173 | // Looked at below, but it requires particular types of Documents. 174 | // http://tugdualgrall.blogspot.co.uk/2015/01/how-to-create-pubsub-application-with.html?m=1 175 | // Instead, simply get latest date from DataLoader, check against last date then notify 176 | 177 | checkDBForUpdates(); 178 | 179 | compareAndNotify(); 180 | 181 | // Sleep for a minute before checking again. 182 | Thread.sleep(m_SleepInterval * 1000); 183 | } 184 | } 185 | } 186 | 187 | catch (IOException | InterruptedException | ParseException e) 188 | { 189 | if (m_CompleteHandler != null) 190 | { 191 | m_CompleteHandler.exceptionRaised("Thread Exception: " + e.getLocalizedMessage()); 192 | } 193 | } 194 | finally 195 | { 196 | if (m_CompleteHandler != null) 197 | { 198 | m_CompleteHandler.dataLoadComplete(m_CompleteHandler.getM_Object()); 199 | } 200 | } 201 | m_LoadRunning = false; 202 | m_Lock.notifyAll(); 203 | 204 | // Kill the thread 205 | // m_LoadThread.interrupt(); 206 | } 207 | } 208 | 209 | /** 210 | * @return the m_LoadRunning 211 | */ 212 | public Boolean getM_LoadRunning() { 213 | return m_LoadRunning; 214 | } 215 | 216 | /** 217 | * @param m_LoadRunning the m_LoadRunning to set 218 | */ 219 | public void setM_LoadRunning(Boolean m_LoadRunning) { 220 | this.m_LoadRunning = m_LoadRunning; 221 | } 222 | 223 | /** 224 | * @return the m_DataLoader 225 | */ 226 | public synchronized DataLoadBase getM_DataLoader() { 227 | return m_DataLoader; 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /src/main/java/loader/DataLoadMedtronic.java: -------------------------------------------------------------------------------- 1 | package loader; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | import control.MyLogger; 11 | import entity.DBResult; 12 | import entity.DBResultMedtronic; 13 | import entity.DBResultMedtronicNew; 14 | import entity.DBResultMedtronicOld; 15 | 16 | public class DataLoadMedtronic extends DataLoadCSVFile 17 | { 18 | private static final Logger m_Logger = Logger.getLogger(MyLogger.class.getName()); 19 | private static final String m_MedtronicSplitBy = "[,;]"; 20 | 21 | private static Boolean m_OldFileFormat = false; 22 | private static Boolean m_NewFileFormat = false; 23 | 24 | 25 | @Override 26 | protected DBResult makeDBResult(String[] res) 27 | { 28 | DBResultMedtronic result = null; 29 | 30 | if (m_OldFileFormat == true) result = result == null ? new DBResultMedtronicOld(res) : result; 31 | if (m_NewFileFormat == true) result = result == null ? new DBResultMedtronicNew(res) : result; 32 | 33 | return result; 34 | } 35 | 36 | @Override 37 | protected String loadStringName() 38 | { 39 | return "Medtronic"; 40 | } 41 | 42 | @Override 43 | protected String getSplitBy() 44 | { 45 | return m_MedtronicSplitBy; 46 | } 47 | 48 | public static boolean isMedtronic(String fileName) 49 | { 50 | boolean result = false; 51 | 52 | result = (result == true ? result : isMedtronicOld(fileName)); 53 | result = (result == true ? result : isMedtronicNew(fileName)); 54 | 55 | return result; 56 | } 57 | 58 | 59 | public static boolean isMedtronicOld(String fileName) 60 | { 61 | boolean result = false; 62 | BufferedReader br = null; 63 | String line = ""; 64 | String cvsSplitBy = "[,;]"; 65 | 66 | // Expected Format 67 | boolean ln2Col1PatientInfo = false; 68 | boolean ln3Col1Name = false; 69 | boolean ln4Col1DateRange = false; 70 | boolean ln5Col1Device = false; 71 | boolean ln11Col1Index = false; // 640 72 | boolean ln13Col1Index = false; // Veo 73 | boolean pump = false; 74 | boolean meter = false; 75 | boolean pump_and_meter = false; 76 | 77 | int ln = 0; 78 | int maxLines = 12; 79 | int index = 10; // for 640 & +2 for Veo 80 | int meterpump1 = 6; // Increment index if both meter and pump seen 81 | int meterpump2 = 7; // Increment for each line that Meter is listed 82 | 83 | try 84 | { 85 | br = new BufferedReader(new FileReader(fileName)); 86 | while ((ln <= maxLines) && (line = br.readLine()) != null) 87 | { 88 | ln++; 89 | // use comma as separator 90 | String[] rs = line.split(cvsSplitBy); 91 | 92 | if (ln == 2) 93 | ln2Col1PatientInfo = (rs.length > 0 && rs[0].equals("PATIENT INFO")) ? true : false; 94 | if (ln == 3) 95 | ln3Col1Name = (rs.length > 0 && rs[0].equals("Name")) ? true : false; 96 | if (ln == 4) 97 | ln4Col1DateRange = (rs.length > 0 && rs[0].equals("Report Range")) ? true : false; 98 | if (ln == 5) 99 | ln5Col1Device = (rs.length > 0 && rs[0].equals("DEVICE INFO")) ? true : false; 100 | 101 | if (ln == meterpump1) 102 | { 103 | pump = (pump || (rs.length > 0 && rs[0].equals("Pump:"))) ? true : false; 104 | meter = (meter || (rs.length > 0 && rs[0].equals("Meter:"))) ? true : false; 105 | } 106 | 107 | if (ln == meterpump2) 108 | { 109 | pump = (pump || (rs.length > 0 && rs[0].equals("Pump:"))) ? true : false; 110 | meter = (meter || (rs.length > 0 && rs[0].equals("Meter:"))) ? true : false; 111 | } 112 | 113 | 114 | if (pump && meter && !pump_and_meter) 115 | { 116 | // There could be more than one meter, so allow index to drift forward by one 117 | // each time we see a separate meter line 118 | // 119 | // 19 Feb 2017 120 | // Seen Pump: at line 6 in file from Melanie Mason 121 | index++; 122 | maxLines++; 123 | 124 | pump_and_meter = true; 125 | } 126 | 127 | if (ln == index) 128 | ln11Col1Index = (rs.length > 0 && rs[0].equals("Index")) ? true : false; 129 | if (ln == index + 2) 130 | ln13Col1Index = (rs.length > 0 && rs[0].equals("Index")) ? true : false; 131 | } 132 | 133 | result = (ln2Col1PatientInfo == true && ln3Col1Name == true && ln4Col1DateRange == true && 134 | ln5Col1Device == true && (ln11Col1Index == true || ln13Col1Index == true) ) ? true : false; 135 | 136 | } 137 | catch (FileNotFoundException e) 138 | { 139 | m_Logger.log(Level.SEVERE, "" + "isMedtronic: FileNotFoundException. File " + fileName + " Error " + e.getMessage()); 140 | 141 | e.printStackTrace(); 142 | } 143 | catch (IOException e) 144 | { 145 | m_Logger.log(Level.SEVERE, "" + "isMedtronic: IOException. File " + fileName + " Error " + e.getMessage()); 146 | e.printStackTrace(); 147 | } 148 | finally 149 | { 150 | if (br != null) 151 | { 152 | try 153 | { 154 | br.close(); 155 | } 156 | catch (IOException e) 157 | { 158 | m_Logger.log(Level.SEVERE, "" + "isMedtronic: IOException closing file. File " + fileName + " Error " + e.getMessage()); 159 | e.printStackTrace(); 160 | } 161 | } 162 | } 163 | 164 | m_OldFileFormat = result; 165 | return result; 166 | } 167 | 168 | 169 | public static boolean isMedtronicNew(String fileName) 170 | { 171 | boolean result = false; 172 | BufferedReader br = null; 173 | String line = ""; 174 | String cvsSplitBy = "[,;]"; 175 | 176 | // Expected Format 177 | boolean ln1Col1PatientInfo = false; 178 | boolean ln6Col1Device = false; 179 | boolean ln7Index = false; 180 | 181 | int ln = 0; 182 | int maxLines = 10; 183 | // int index = 10; // for 640 & +2 for Veo 184 | // int meterpump1 = 6; // Increment index if both meter and pump seen 185 | // int meterpump2 = 7; // Increment for each line that Meter is listed 186 | 187 | try 188 | { 189 | br = new BufferedReader(new FileReader(fileName)); 190 | while ((ln <= maxLines) && (line = br.readLine()) != null) 191 | { 192 | ln++; 193 | // use comma as separator 194 | String[] rs = line.split(cvsSplitBy); 195 | 196 | if (ln == 1) 197 | ln1Col1PatientInfo = (rs.length > 0 && rs[0].equals("Last Name")) ? true : false; 198 | if (ln == 6) 199 | ln6Col1Device = (rs.length > 0 && rs[0].equals("-------")) ? true : false; 200 | if (ln == 7) 201 | ln7Index = (rs.length > 0 && rs[0].equals("Index")) ? true : false; 202 | 203 | } 204 | 205 | result = (ln1Col1PatientInfo == true && ln6Col1Device == true && ln7Index == true ) ? true : false; 206 | 207 | } 208 | catch (FileNotFoundException e) 209 | { 210 | m_Logger.log(Level.SEVERE, "" + "isMedtronic: FileNotFoundException. File " + fileName + " Error " + e.getMessage()); 211 | 212 | e.printStackTrace(); 213 | } 214 | catch (IOException e) 215 | { 216 | m_Logger.log(Level.SEVERE, "" + "isMedtronic: IOException. File " + fileName + " Error " + e.getMessage()); 217 | e.printStackTrace(); 218 | } 219 | finally 220 | { 221 | if (br != null) 222 | { 223 | try 224 | { 225 | br.close(); 226 | } 227 | catch (IOException e) 228 | { 229 | m_Logger.log(Level.SEVERE, "" + "isMedtronic: IOException closing file. File " + fileName + " Error " + e.getMessage()); 230 | e.printStackTrace(); 231 | } 232 | } 233 | } 234 | 235 | m_NewFileFormat = result; 236 | return result; 237 | } 238 | 239 | } 240 | 241 | --------------------------------------------------------------------------------