import java.awt.*; import java.awt.event.*; import java.io.*; import java.text.*; import java.lang.System.*; import java.util.zip.*; /*Data File Structure IMPORTANT Added by WH "long" as used in the data description has 4 bytes. numbers are coded bigendian This is the original documentation by WeatherLink: What follows is a technical description of the .WLK weather database files. This is of interest mostly to programmers who want to write their own programs to read the data files. The data filename has the following format: YYYY-MM.wlk where YYYY is the four digit year and MM is the two digit month of the data contained in the file. The structures defined below assume that no bytes are added to the structures to make the fields are on the "correct" address boundaries. With the Microsoft C++ compiler, you can use the directive "#pragma pack (1)" to enforce this and use "#pragma pack ()" to return the compiler to its default behavior. // Data is stored in monthly files. Each file has the following header. struct DayIndex { short recordsInDay; // includes any daily summary records long startPos; // The index (starting at 0) of the first daily summary record }; // Header for each monthly file. // The first 16 bytes are used to identify a weather database file and to identify // different file formats. (Used for converting older database files.) class HeaderBlock { char idCode [16]; // = {'W', 'D', 'A', 'T', '5', '.', '0', 0, 0, 0, 0, 0, 0, 0, 5, 0} ***** or rather = {'W', 'D', 'A', 'T', '5', '.', '3', 0, 0, 0, 0, 0, 0, 0, 5, 3} long totalRecords; DayIndex dayIndex [32]; // index records for each day. Index 0 is not used // (i.e. the 1'st is at index 1, not index 0) }; // After the Header are a series of 88 byte data records with one of the following // formats. Note that each day will begin with 2 daily summary records // Daily Summary Record 1 struct DailySummary1 { BYTE dataType = 2; BYTE reserved; // this will cause the rest of the fields to start on an even address short dataSpan; // total # of minutes accounted for by physical records for this day short hiOutTemp, lowOutTemp; // tenths of a degree F short hiInTemp, lowInTemp; // tenths of a degree F short avgOutTemp, avgInTemp; // tenths of a degree F (integrated over the day) short hiChill, lowChill; // tenths of a degree F short hiDew, lowDew; // tenths of a degree F short avgChill, avgDew; // tenths of a degree F short hiOutHum, lowOutHum; // tenths of a percent short hiInHum, lowInHum; // tenths of a percent short avgOutHum; // tenths of a percent short hiBar, lowBar; // thousandths of an inch Hg short avgBar; // thousandths of an inch Hg short hiSpeed, avgSpeed; // tenths of an MPH short dailyWindRunTotal; // 1/10'th of an mile short hi10MinSpeed; // the highest average wind speed record BYTE dirHiSpeed, hi10MinDir; // direction code (0-15, 255) short dailyRainTotal; // 1/1000'th of an inch short hiRainRate; // 1/100'th inch/hr ??? short dailyUVDose; // 1/10'th of a standard MED BYTE hiUV; // tenth of a UV Index BYTE timeValues[27]; // space for 18 time values (see below) }; // Daily Summary Record 2 struct DailySummary2 { BYTE dataType = 3; BYTE reserved; // this will cause the rest of the fields to start on an even address // this field is not used now. unsigned short todaysWeather; // bitmapped weather conditions (Fog, T-Storm, hurricane, etc) short numWindPackets; // # of valid packets containing wind data, // this is used to indicate reception quality short hiSolar; // Watts per meter squared short dailySolarEnergy; // 1/10'th Ly short minSunlight; // number of accumulated minutes where the avg solar rad > 150 short dailyETTotal; // 1/1000'th of an inch short hiHeat, lowHeat; // tenths of a degree F short avgHeat; // tenths of a degree F short hiTHSW, lowTHSW; // tenths of a degree F short hiTHW, lowTHW; // tenths of a degree F short integratedHeatDD65; // integrated Heating Degree Days (65F threshold) // tenths of a degree F - Day // Wet bulb values are not calculated short hiWetBulb, lowWetBulb; // tenths of a degree F short avgWetBulb; // tenths of a degree F BYTE dirBins[24]; // space for 16 direction bins // (Used to calculate monthly dominant Dir) BYTE timeValues[15]; // space for 10 time values (see below) short integratedCoolDD65; // integrated Cooling Degree Days (65F threshold) // tenths of a degree F - Day BYTE reserved2[11]; }; // standard archive record struct WeatherDataRecord { BYTE dataType = 1; BYTE archiveInterval; // number of minutes in the archive // see below for more details about these next two fields) BYTE iconFlags; // Icon associated with this record, plus Edit flags BYTE moreFlags; // Tx Id, etc. short packedTime; // minutes past midnight of the end of the archive period short outsideTemp; // tenths of a degree F short hiOutsideTemp; // tenths of a degree F short lowOutsideTemp; // tenths of a degree F short insideTemp; // tenths of a degree F short barometer; // thousandths of an inch Hg short outsideHum; // tenths of a percent short insideHum; // tenths of a percent unsigned short rain; // number of clicks + rain collector type code short hiRainRate; // clicks per hour short windSpeed; // tenths of an MPH short hiWindSpeed; // tenths of an MPH BYTE windDirection; // direction code (0-15, 255) BYTE hiWindDirection; // direction code (0-15, 255) short numWindSamples; // number of valid ISS packets containing wind data // this is a good indication of reception short solarRad, hisolarRad;// Watts per meter squared BYTE UV, hiUV; // tenth of a UV Index BYTE leafTemp[4]; // (whole degrees F) + 90 short extraRad; // used to calculate extra heating effects of the sun in THSW index short newSensors[6]; // reserved for future use BYTE forecast; // forecast code during the archive interval BYTE ET; // in thousandths of an inch BYTE soilTemp[6]; // (whole degrees F) + 90 BYTE soilMoisture[6]; // centibars of dryness BYTE leafWetness[4]; // Leaf Wetness code (0-15, 255) BYTE extraTemp[7]; // (whole degrees F) + 90 BYTE extraHum[7]; // whole percent }; Notes: Always check the dataType field to make sure you are reading the correct record type There are extra fields that are not used by the current software. For example, there is space for 7 extra temperatures and Hums, but current Vantage stations only log data for 3 extra temps and 2 extra hums. Extra/Soil/Leaf temperatures are in whole degrees with a 90 degree offset. A database value of 0 = -90 F, 100 = 10 F, etc. The rain collector type is encoded in the most significant nibble of the rain field. rainCollectorType = (rainCode & 0xF000); rainClicks = (rainCode & 0x0FFF); Type rainCollectorType 0.1 inch 0x0000 ***WH: first Byte: 0 0.01 inch 0x1000 ***WH: first Byte: 16 0.2 mm 0x2000 ***WH: first Byte: 32 1.0 mm 0x3000 ***WH: first Byte: 48 0.1 mm 0x6000 (not fully supported) ***WH: first Byte: 96 Use the rainCollectorType to interpret the hiRainRate field. For example, if you have a 0.01 in rain collector, a rain rate value of 19 = 0.19 in/hr = 4.8 mm/hr, but if you have a 0.2 mm rain collector, a rain rate value of 19 = 3.8 mm/hr = 0.15 in/hr. Format for the iconFlags field The lower nibble will hold a value that will represent an Icon to associate with this data record (i.e. snow, rain, sun, lightning, etc.). This field is not used. Bit (0x10) is set if the user has used the edit record function to change a data value. This allows tracking of edited data. Bit (0x20) is set if there is a data note associated with the archive record. If there is, it will be found in a text file named YYYYMMDDmmmm.NOTE. YYYY is the four digit year, MM is the two digit month (i.e. Jan = 01), DD is the two digit day, and mmmm is the number of minutes past midnight (i.e. the packedTime field). This file is found in the DATANOTE subdirectory of the station directory. Format for the moreFlags field The lowest 3 bits contain the transmitter ID that is the source of the wind speed packets recorded in the numWindSamples field. This value is between 0 and 7. If your ISS is on ID 1, zero will be stored in this field. WindTxID = (moreFlags & 0x07); Time values and Wind direction values in Daily Summary records These values are between 0 and 1440 and therefore will fit in 1 1/2 bytes, and 2 values fit in 3 bytes. Use this code to extract the i'th time or direction value. See below for the list of i values. fieldIndex = (i/2) * 3; // note this is integer division (rounded down) if (i is even) value = field[fieldIndex] + (field[fieldIndex+2] & 0x0F)<<8; if (i is odd) value = field[fieldIndex+1] + (field[fieldIndex+2] & 0xF0)<<4; A value of 0x0FFF or 0x07FF indicates no data available (i.e. invalid data) The time value represents the number of minutes after midnight that the specified event took place (actually the time of the archive record). The wind direction bins represent the number of minutes that that direction was the dominant wind direction for the day. Index values for Daily Summary Record 1 time values Time of High Outside Temperature 0 Time of Low Outside Temperature 1 Time of High Inside Temperature 2 Time of Low Inside Temperature 3 Time of High Wind Chill 4 Time of Low Wind Chill 5 Time of High Dew Point 6 Time of Low Dew Point 7 Time of High Outside Humidity 8 Time of Low Outside Humidity 9 Time of High Inside Humidity 10 Time of Low Inside Humidity 11 Time of High Barometer 12 Time of Low Barometer 13 Time of High Wind Speed 14 Time of High Average Wind Speed 15 Time of High Rain Rate 16 Time of High UV 17 Index values for Daily Summary Record 2 time values Time of High Solar Rad 0 Time of High Outside Heat Index 1 Time of Low Outside Heat Index 2 Time of High Outside THSW Index 3 Time of Low Outside THSW Index 4 Time of High Outside THW Index 5 Time of Low Outside THW Index 6 Time of High Outside Wet Bulb Temp 7 Time of Low Outside Wet Bulb Temp 8 (Time value 9 is not used) Index values for Dominant Wind direction bins in Daily Summary Record 2 N 0 NNE 1 NE 2 ... NW 14 NNW 15 */ public class WLK_Translator extends Frame { String outLine; public String sLine = ""; public String sWholeText = ""; public String sSummariesText = ""; boolean fComponentsAdjusted = false; java.awt.Button btnOpen; java.awt.Button btnWork; java.awt.Label myText; java.awt.Label label2; Checkbox chkSummaries; Checkbox chkRecalculate; CheckboxGroup chkDecimalPoint; Checkbox chkComma; Checkbox chkPoint; public static WLK_Translator mf = new WLK_Translator(); String theDir = ""; String theFile = ""; byte[] header = new byte[212]; byte[] records = new byte[88]; int[] recordsPerDay = new int[32]; int[] startOfRecord = new int[32]; int headerOffset = 20; int dayRecordOffset = 212; int totalRecords = 0; int recordsInDay = 0; int startPos = 1; private static String nl = System.getProperty("line.separator"); BufferedOutputStream out; FileInputStream zin = null; boolean onlySummary = true; boolean bRecalculate = true; boolean bDecimalComma = true; private void addCheckbox(Panel p, String name, String lb, CheckboxGroup g, boolean v) { Checkbox c = new Checkbox(name, g, v); c.setLabel(lb); c.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent evt) { if (evt.getStateChange() == ItemEvent.DESELECTED) return; if (evt.getItem().equals("chkComma")) bDecimalComma = true; if (evt.getItem().equals("chkPoint")) bDecimalComma = false; System.out.println("Komma? " + bDecimalComma); } }); p.add(c); } public WLK_Translator() { setLayout(null); setVisible(false); setSize(getInsets().left + getInsets().right + 305, getInsets().top + getInsets().bottom + 420); setBackground(new Color(-1973791)); setTitle("Interpreter for Davis wlk-Files"); btnOpen = new java.awt.Button(); btnOpen.setActionCommand("button"); btnOpen.setLabel("open file"); btnOpen.setBounds(getInsets().left + 38, getInsets().top + 32,228,28); btnOpen.setBackground(new Color(12632256)); add(btnOpen); label2 = new java.awt.Label (""); label2.setBounds(getInsets().left + 38, getInsets().top + 72,228,28); //label2.setBackground(new Color(12632256)); add(label2); btnWork = new java.awt.Button(); btnWork.setActionCommand("button"); btnWork.setLabel("translate"); btnWork.setBounds(getInsets().left + 38, getInsets().top + 152,228,28); btnWork.setBackground(new Color(12632256)); add(btnWork); chkSummaries = new Checkbox(); chkSummaries.setLabel("only summaries"); chkSummaries.setState(true); chkSummaries.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent evt) { if ( chkSummaries.getState() == true) onlySummary = true; else onlySummary = false; } }); chkSummaries.setBounds(getInsets().left + 38, getInsets().top + 192,228,28); add(chkSummaries); chkRecalculate = new Checkbox(); chkRecalculate.setLabel("recalculate raw data to °C / mm / km/h / mmHg"); chkRecalculate.setState(true); chkRecalculate.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent evt) { if ( chkRecalculate.getState() == true) bRecalculate = true; else bRecalculate = false; } }); chkRecalculate.setBounds(getInsets().left + 38, getInsets().top + 232,228,28); add(chkRecalculate); Panel pc = new Panel(); pc.setBounds(getInsets().left + 38, getInsets().top + 272, 228, 68); pc.setLayout(new GridLayout(2, 1)); chkDecimalPoint = new CheckboxGroup(); addCheckbox(pc, "chkComma", "decimal: comma", chkDecimalPoint, true); addCheckbox(pc, "chkPoint", "decimal: point", chkDecimalPoint, false); add(pc); myText = new java.awt.Label (""); myText.setBounds(getInsets().left + 44, getInsets().top + 342,228,28); //myText.setBackground(new Color(12632256)); add(myText); MyWindow aSymWindow = new MyWindow(); this.addWindowListener(aSymWindow); MyMouse aSymMouse = new MyMouse(); btnOpen.addMouseListener(aSymMouse); btnWork.addMouseListener(aSymMouse); //}} } public WLK_Translator(String title) { this(); setTitle(title); //setBackground(new Color(12632256)); } /** * Shows or hides the component depending on the boolean flag b. * @param b if true, show the component; otherwise, hide the component. * @see java.awt.Component#isVisible */ public void setVisible(boolean b) { if(b) { setLocation(50, 50); } super.setVisible(b); } static public void main(String args[]) { try { //Create a new instance of our application's frame, and make it visible. WLK_Translator myFrame = new WLK_Translator(); myFrame.setVisible(true); try { if (args[0].length() > 0) { myFrame.btnOpen.setEnabled(false); myFrame.theFile = args[0]; myFrame.openingdetails(args[0]); } } catch (Exception e){} } catch (Throwable t) { System.err.println(t); t.printStackTrace(); //Ensure the application exits with an error condition. System.exit(1); } } public void addNotify() { // Record the size of the window prior to calling parents addNotify. Dimension d = getSize(); super.addNotify(); if (fComponentsAdjusted) return; // Adjust components according to the insets setSize(getInsets().left + getInsets().right + d.width, getInsets().top + getInsets().bottom + d.height); Component components[] = getComponents(); for (int i = 0; i < components.length; i++) { Point p = components[i].getLocation(); p.translate(getInsets().left, getInsets().top); components[i].setLocation(p); } fComponentsAdjusted = true; } class MyWindow extends java.awt.event.WindowAdapter { public void windowClosing(java.awt.event.WindowEvent event) { Object object = event.getSource(); if (object == WLK_Translator.this) WLK_Translator_WindowClosing(event); } } void WLK_Translator_WindowClosing(java.awt.event.WindowEvent event) { setVisible(false); // hide the Frame dispose(); // free the system resources System.exit(0); // close the application } class MyMouse extends java.awt.event.MouseAdapter { public void mouseClicked(java.awt.event.MouseEvent event) { Object object = event.getSource(); if (object == btnOpen) btnOpen_MouseClick(event); if (object == btnWork) btnWork_MouseClick(event); } } void btnOpen_MouseClick(java.awt.event.MouseEvent event) { FileDialog d = new FileDialog(this, "öffnen", FileDialog.LOAD); d.setVisible(true); theDir = d.getDirectory(); theFile = d.getFile(); openingdetails(theFile); } public void openingdetails(String theFile) { int iLen = theFile.length(); if (theFile.substring(iLen-4, iLen).equals(".wlk")) { btnWork.setEnabled(true); label2.setText("opened: "+theFile); } else { myText.setText("not a wlk file!"); btnWork.setEnabled(false); return; } myText.setText(""); } void btnWork_MouseClick(java.awt.event.MouseEvent event) { btnWork.setEnabled(false); btnOpen.setEnabled(false); extract(theDir + theFile); myText.setText("done"); btnWork.setEnabled(true); btnOpen.setEnabled(true); } public String extract(String path) { sWholeText = ""; sSummariesText = ""; try { zin = new FileInputStream(path); int iBytesRead = 0; int ictr = 0; iBytesRead = readHeaderBlock(path); zin.close(); if (totalRecords < 10000) { writingValue_1(theDir + theFile); } writingValue_2(theDir + theFile); } catch(IOException e) { } return "not found"; } private int readHeaderBlock(String path) { int iBytesRead = -1; try{ iBytesRead = zin.read(header, 0, 212); char[] idCode = new char[16]; // = {'W', 'D', 'A', 'T', '5', '.', '3', 0, 0, 0, 0, 0, 0, 0, 5, 3} for (int i=0; i<16; i++) { idCode[i] = (char)header[i]; //sWholeText += " " + idCode[i];//.toString(); } totalRecords = byteToInt(rebuffering(header, 16, 4)); //sWholeText += " totalRecords " + totalRecords; System.out.println(" totalRecords " + totalRecords); for (int i=0; i<32; i++) readDayIndex(header, i, path); } catch (Exception e) { System.out.println("Exception readHeaderBlock " + e); } return iBytesRead; } private void readDayIndex(byte[] header, int iDay, String path) { recordsPerDay[iDay] = byteToShort(rebuffering(header, headerOffset + iDay * 6, 2)) ; startOfRecord[iDay] = byteToInt(rebuffering(header, headerOffset + 2 + iDay * 6, 4)) ; if (totalRecords < 10000) sWholeText += nl + " iDay: " + iDay + " recordsInDay: " + recordsPerDay[iDay] + " startPos: " + startOfRecord[iDay] + " "; else sWholeText = " iDay: " + iDay + " recordsInDay: " + recordsPerDay[iDay] + " startPos: " + startOfRecord[iDay] + " "; System.out.println(" recordsInDay: " + recordsPerDay[iDay]); sSummariesText += nl + iDay; try{ for (int i=0; i= 10000) writingValue_1(theDir + theFile + (iDay<10? "0" +iDay : "" + iDay)); } private int readWeatherDataRecord(FileInputStream zin, int iDay) // 88 bytes { int iBytesRead = -1; try{ iBytesRead = zin.read(records); } catch (Exception e) { System.out.println("Exception readWeatherDataRecord " + e); } if (records[0] == 1 && !onlySummary) { readType_1_Record(); } if (records[0] == 2) { readType_2_Record(iDay); } if (records[0] == 3) { readType_3_Record(iDay); } return iBytesRead; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // standard data record: private void readType_1_Record() { short archiveInterval = (short)(records[1]<0?records[1] + 256: records[1]); // number of minutes in the archive //byte iconFlags; // Icon associated with this record, plus Edit flags //byte moreFlags; // Tx Id, etc. short packedTime = byteToShort(rebuffering(records, 4, 2)); // minutes past midnight of the end of the archive period short outsideTemp = byteToShort(rebuffering(records, 6, 2)); // tenths of a degree F short hiOutsideTemp = byteToShort(rebuffering(records, 8, 2)); // tenths of a degree F short lowOutsideTemp = byteToShort(rebuffering(records, 10, 2)); // tenths of a degree F //short insideTemp = toShort(12); // tenths of a degree F short barometer = byteToShort(rebuffering(records, 14, 2)); // thousandths of an inch Hg short outsideHum = byteToShort(rebuffering(records, 16, 2)); // tenths of a percent //short insideHum = toShort(18); // tenths of a percent int rainClicks = records[20]; rainClicks = (rainClicks<0?rainClicks+256:rainClicks); // number of clicks int rainCollectorType = records[21]; // rain collector type code int overspill = rainCollectorType % 16; if (overspill != 0) rainClicks = overspill * 256 + rainClicks; rainCollectorType = rainCollectorType / 16; short hiRainRate = byteToShort(rebuffering(records, 22, 2)); // clicks per hour short windSpeed = byteToShort(rebuffering(records, 24, 2)); // tenths of an MPH short hiWindSpeed = byteToShort(rebuffering(records, 26, 2)); // tenths of an MPH short windDirection = (short)(records[28]<0?records[28] + 256: records[28]); // direction code (0-15, 255) short hiWindDirection = (short)(records[29]<0?records[29] + 256: records[29]); // direction code (0-15, 255) /*short numWindSamples; // number of valid ISS packets containing wind data */ // this is a good indication of reception // solar radiation not yet tested! short solarRad = byteToShort(rebuffering(records, 32, 2)); short hisolarRad = byteToShort(rebuffering(records, 34, 2)); // Watts per meter squared /*byte UV, hiUV; // tenth of a UV Index byte leafTemp[4]; // (whole degrees F) + 90 short extraRad; // used to calculate extra heating effects of the sun in THSW index short newSensors[6]; // reserved for future use byte forecast; // forecast code during the archive interval byte ET; // in thousandths of an inch byte soilTemp[6]; // (whole degrees F) + 90 byte soilMoisture[6]; // centibars of dryness byte leafWetness[4]; // Leaf Wetness code (0-15, 255) byte extraTemp[7]; // (whole degrees F) + 90 byte extraHum[7]; // whole percent */ sLine = ""; if (!bRecalculate) { sLine += nl + archiveInterval + "\t" + packedTime + "\t" + outsideTemp + "\t" + hiOutsideTemp + "\t" + lowOutsideTemp + "\t"; sLine += barometer + "\t" + outsideHum + "\t" + rainCollectorType + "\t" + rainClicks + "\t" + hiRainRate + "\t"; sLine += windSpeed + "\t" + hiWindSpeed + "\t" + windDirection + "\t" + hiWindDirection + "\t" + solarRad+ "\t" + hisolarRad;// + "\t" + solarRad + "\t" + hisolarRad; } else { sLine += nl + archiveInterval + "\t" + (packedTime / 60) + ":" + (packedTime % 60); sLine += "\t" + ((((float)outsideTemp)/10-32)*5/9); sLine += "\t" + ((((float)hiOutsideTemp)/10-32)*5/9) + "\t" + ((((float)lowOutsideTemp)/10-32)*5/9) + "\t"; sLine += ((float)barometer/100*2.54*1.333224) + "\t" + ((float)outsideHum / 10) + "\t" + rainCollectorType + "\t"; switch (rainCollectorType) { case 0: sLine += ((float)rainClicks*2.54) + "\t"; //0.1 inch 0x0000 ***WH: first Byte: 0 break; case 1: sLine += ((float)rainClicks*0.254) + "\t"; //0.01 inch 0x1000 ***WH: first Byte: 16 break; case 2: sLine += ((float)rainClicks/5) + "\t"; //0.2 mm 0x2000 ***WH: first Byte: 32 break; case 3: sLine += ((float)rainClicks) + "\t"; //1.0 mm 0x3000 ***WH: first Byte: 48 break; case 4: sLine += ((float)rainClicks/10) + "\t"; //0.1 mm 0x6000 ***WH: first Byte: 96 break; } sLine += hiRainRate + "\t"; sLine += ((float)windSpeed/10*1.6093) + "\t" + ((float)hiWindSpeed/10*1.6093) + "\t"; sLine += decodeWindDirCode(windDirection) + "\t" + decodeWindDirCode(hiWindDirection);// + "\t" + solarRad + "\t" + hisolarRad; sLine += "\t" + solarRad+ "\t" + hisolarRad; } if (bDecimalComma) sLine = replaceDecimalPt(sLine); sWholeText += sLine; } private String decodeWindDirCode(int windDirCode) { switch (windDirCode) { case 0: return "N"; case 1: return "NNE"; case 2: return "NE"; case 3: return "ENE"; case 4: return "E"; case 5: return "ESE"; case 6: return "SE"; case 7: return "SSE"; case 8: return "S"; case 9: return "SSW"; case 10: return "SW"; case 11: return "WSW"; case 12: return "W"; case 13: return "WNW"; case 14: return "NW"; case 15: return "NNW"; } return "-"; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // summary part 1: private void readType_2_Record(int iDay) { //BYTE dataType = 2; //BYTE reserved; // this will cause the rest of the fields to start on an even address short dataSpan = byteToShort(rebuffering(records, 2, 2)); // total # of minutes accounted for by physical records for this day short hiOutTemp = byteToShort(rebuffering(records, 4, 2)); // tenths of a degree F short lowOutTemp = byteToShort(rebuffering(records, 6, 2)); // tenths of a degree F //short hiInTemp, lowInTemp; // tenths of a degree F short avgOutTemp = byteToShort(rebuffering(records, 12, 2)); // tenths of a degree F // avgInTemp; // tenths of a degree F (integrated over the day) /*short hiChill, lowChill; // tenths of a degree F short hiDew, lowDew; // tenths of a degree F short avgChill, avgDew; // tenths of a degree F */ short hiOutHum = byteToShort(rebuffering(records, 28, 2)); // tenths of a percent short lowOutHum = byteToShort(rebuffering(records, 30, 2)); // tenths of a percent //short hiInHum, lowInHum; // tenths of a percent short avgOutHum = byteToShort(rebuffering(records, 36, 2)); // tenths of a percent short hiBar = byteToShort(rebuffering(records, 38, 2)); // thousandths of an inch Hg short lowBar = byteToShort(rebuffering(records, 40, 2)); // thousandths of an inch Hg short avgBar = byteToShort(rebuffering(records, 42, 2)); // thousandths of an inch Hg short hiSpeed = byteToShort(rebuffering(records, 44, 2)); // tenths of an MPH short avgSpeed = byteToShort(rebuffering(records, 46, 2)); // tenths of an MPH //short dailyWindRunTotal; // 1/10'th of an mile short hi10MinSpeed = byteToShort(rebuffering(records, 50, 2)); // the highest average wind speed record short dirHiSpeed = (short)(records[52]<0?records[52] + 256: records[52]); // direction code (0-15, 255) //byte hi10MinDir; // direction code (0-15, 255) short dailyRainTotal = byteToShort(rebuffering(records, 54, 2)); // 1/1000'th of an inch /*short hiRainRate; // 1/100'th inch/hr ??? short dailyUVDose; // 1/10'th of a standard MED byte hiUV; */ // tenth of a UV Index //byte timeValues[27]; // space for 18 time values (see below) short timeHiTemp = 0x0FFF; //Time of High Outside Temperature 0 short timeLoTemp = 0x0FFF; //Time of Low Outside Temperature 1 /* Time of High Inside Temperature 2 Time of Low Inside Temperature 3 Time of High Wind Chill 4 Time of Low Wind Chill 5 Time of High Dew Point 6 Time of Low Dew Point 7 */ short timeHiHum = 0x0FFF; //Time of High Outside Humidity 8 short timeLoHum = 0x0FFF; //Time of Low Outside Humidity 9 // Time of High Inside Humidity 10 // Time of Low Inside Humidity 11 short timeHiBar = 0x0FFF; //Time of High Barometer 12 short timeLoBar = 0x0FFF; //Time of Low Barometer 13 short timeHiSpeed = 0x0FFF; /*Time of High Wind Speed 14 Time of High Average Wind Speed 15 Time of High Rain Rate 16 Time of High UV 17 */ for (int k=0; k<18; k++) { int fieldIndex = (k/2) * 3 + 61; // note this is integer division (rounded down) short s1 = records[fieldIndex]; short s2 = (short)((records[fieldIndex+2] & 0x0f)); short value = 0; // if (iDay == 23 && k<3) // System.out.println(records[fieldIndex] + " " + records[fieldIndex+1] + " " + records[fieldIndex+2]); if (k % 2 == 0) { s1 = s1<0?(short)(s1+256):s1; s2 = s2 < 0? (short)(s2 + 16): s2; value = (short)(s1 + s2 * 256); //if (iDay == 23 && k<3) // System.out.println(" xx even " + s1 + " " + s2+ " " + value); /*if (iDay==1 && k<3) { System.out.println(records[fieldIndex] + " " + records[fieldIndex+1] + " " + records[fieldIndex+2]); System.out.println(s1 + " " + s2 + " " +value); } */ } if (k % 2 == 1) { s1 = records[fieldIndex+1]; s2 = (short)((records[fieldIndex+2] & 0xf0)>>4); s1 = s1<0?(short)(s1+256):s1; s2 = s2 < 0? (short)(s2 + 16): s2; value = (short)(s1 + s2 * 256); //if (iDay == 23 && k<3) // System.out.println(" xx odd " + s1 + " " + s2+ " " + value); /*if (iDay==1 && k<3) { System.out.println(records[fieldIndex] + " " + records[fieldIndex+1] + " " + records[fieldIndex+2]); System.out.println(s1 + " " + s2 + " " +value); } */ } switch (k) { case 0: timeHiTemp = value; break; case 1: timeLoTemp = value; break; //' missing cases presently not used case 8: timeHiHum = value; break; case 9: timeLoHum = value; break; case 12: timeHiBar = value; break; case 13: timeLoBar = value; break; case 14: timeHiSpeed = value; break; } } sLine = ""; if (!bRecalculate) { sLine += "\t" + dataSpan + "\t" + hiOutTemp + "\t" + lowOutTemp + "\t" + avgOutTemp; sLine += "\t" + hiOutHum + "\t" + lowOutHum + "\t" +avgOutHum + "\t" + hiBar + "\t" + lowBar + "\t" +avgBar; sLine += "\t" + hiSpeed + "\t" + avgSpeed + "\t" + dirHiSpeed + "\t" + hi10MinSpeed + "\t"; sLine += dailyRainTotal + "\t" + timeHiTemp; sLine += "\t" + timeLoTemp + "\t" + timeHiHum + "\t" + timeLoHum + "\t" + timeHiBar + "\t" + timeLoBar + "\t" + timeHiSpeed ; } else { sLine += "\t" + dataSpan + "\t" + ((((float)hiOutTemp)/10-32)*5/9); sLine += "\t" + ((((float)lowOutTemp)/10-32)*5/9) + "\t" + ((((float)avgOutTemp)/10-32)*5/9) + "\t"; sLine += ((float)hiOutHum / 10) + "\t" + ((float)lowOutHum / 10) + "\t" + ((float)avgOutHum / 10) + "\t"; sLine += ((float)hiBar/100*2.54*1.333224) + "\t" + ((float)lowBar/100*2.54*1.333224) + "\t"; sLine +=((float)avgBar/100*2.54*1.333224) + "\t"; sLine += ((float)hiSpeed/10*1.6093) + "\t" + ((float)avgSpeed/10*1.6093) + "\t" + dirHiSpeed + "\t"; sLine += ((float)hi10MinSpeed/10*1.6093) + "\t"; sLine += ((float)dailyRainTotal/100*2.54) + "\t" + "'" + (timeHiTemp / 60) + ":" + (timeHiTemp % 60) + "\t"; sLine += "'" + (timeLoTemp / 60) + ":" + (timeLoTemp % 60) + "\t" + "'" + (timeHiHum / 60) + ":" + (timeHiHum % 60) + "\t"; sLine += "'" + (timeLoHum / 60) + ":" + (timeLoHum % 60) + "\t"; sLine += "'" + (timeHiBar / 60) + ":" + (timeHiBar % 60) + "\t" + "'" + (timeLoBar / 60) + ":" + (timeLoBar % 60) + "\t"; sLine += "'" + (timeHiSpeed / 60) + ":" + (timeHiSpeed % 60) + "\t" ; } if (bDecimalComma) sLine = replaceDecimalPt(sLine); sSummariesText += sLine; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // summary part 2: private void readType_3_Record(int iDay) { /* BYTE dataType = 3; BYTE reserved; // this will cause the rest of the fields to start on an even address // this field is not used now. unsigned short todaysWeather; // bitmapped weather conditions (Fog, T-Storm, hurricane, etc) short numWindPackets; // # of valid packets containing wind data, // this is used to indicate reception quality */ short hiSolar = byteToShort(rebuffering(records, 6, 2)); // Watts per meter squared short dailySolarEnergy = byteToShort(rebuffering(records, 8, 2)); // 1/10'th Ly short minSunlight = byteToShort(rebuffering(records, 10, 2)); // number of accumulated minutes where the avg solar rad > 150 /*short dailyETTotal; // 1/1000'th of an inch short hiHeat, lowHeat; // tenths of a degree F short avgHeat; // tenths of a degree F short hiTHSW, lowTHSW; // tenths of a degree F short hiTHW, lowTHW; // tenths of a degree F short integratedHeatDD65; // integrated Heating Degree Days (65F threshold) // tenths of a degree F - Day // Wet bulb values are not calculated short hiWetBulb, lowWetBulb; // tenths of a degree F short avgWetBulb; // tenths of a degree F */ //BYTE dirBins[24]; int[] direction = new int[16]; // space for 16 direction bins // (Used to calculate monthly dominant Dir) for (int k=0; k<16; k++) { int fieldIndex = (k/2) * 3 + 36; // note this is integer division (rounded down) short s1 = records[fieldIndex]; short s2 = (short)(records[fieldIndex + 2] & 0x0f); short value = 0; if ((k % 2) == 0) { s1 = (s1<0?(short)(s1+256):s1); s2 = (s2 < 0? (short)(s2 + 16): s2); direction[k] = (short)(s1 + s2 * 256); } if ((k % 2) == 1) { s1 = records[fieldIndex + 1]; s2 = (short)((records[fieldIndex + 2] & 0xf0)>>4); s1 = s1<0?(short)(s1+256):s1; s2 = s2 < 0? (short)(s2 + 16): s2; direction[k] = (short)(s1 + s2 * 256); } //if (iDay == 1 && k<7) // System.out.println(((k % 2) == 0) + " " +records[fieldIndex] + " " + records[fieldIndex+1] + " " + records[fieldIndex+2] + " " + s1 + " " + s2); } /*BYTE timeValues[15]; // space for 10 time values (see below) */ // time values not tested!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! short timeHiSolarRad = 0x0FFF; //Time of High Solar Rad 0 //Time of High Outside Heat Index 1 //Time of Low Outside Heat Index 2 //Time of High Outside THSW Index 3 //Time of Low Outside THSW Index 4 //Time of High Outside THW Index 5 //Time of Low Outside THW Index 6 //Time of High Outside Wet Bulb Temp 7 //Time of Low Outside Wet Bulb Temp 8 //(Time value 9 is not used) for (int k=0; k<10; k++) { int fieldIndex = (k/2) * 3 + 58; // note this is integer division (rounded down) short s1 = records[fieldIndex]; short s2 = (short)((records[fieldIndex+2] & 0x0f)); short value = 0; if (k % 2 == 0) { s1 = s1<0?(short)(s1+256):s1; s2 = s2 < 0? (short)(s2 + 16): s2; value = (short)(s1 + s2 * 256); } if (k % 2 == 1) { s1 = records[fieldIndex+1]; s2 = (short)((records[fieldIndex+2] & 0xf0)>>4); s1 = s1<0?(short)(s1+256):s1; s2 = s2 < 0? (short)(s2 + 16): s2; value = (short)(s1 + s2 * 256); } switch (k) { case 0: timeHiSolarRad = value; break; //' missing cases presently not used } } /* short integratedCoolDD65; // integrated Cooling Degree Days (65F threshold) // tenths of a degree F - Day BYTE reserved2[11]; */ sLine = ""; if (!bRecalculate) { sLine += hiSolar + "\t" + dailySolarEnergy + "\t" + minSunlight; } else { sLine += hiSolar + "\t" + (float)dailySolarEnergy / 10 + "\t" + minSunlight; } for (int i=0; i<16; i++) sLine += "\t" + direction[i]; sLine += "\t" + "'" + (timeHiSolarRad / 60) + ":" + (timeHiSolarRad % 60); if (bDecimalComma) sLine = replaceDecimalPt(sLine); sSummariesText += sLine; } private static String replaceDecimalPt(String sLine) { String sLeft = ""; String sRight = sLine; int iPos = 0; iPos = sRight.indexOf("."); while (iPos > -1) { sLeft = sLeft + sRight.substring(0, iPos) + ","; sRight = sRight.substring(iPos + 1, sRight.length()); //System.out.println(" " + sLeft + " " + sRight+ " "); iPos = sRight.indexOf("."); } //System.out.println(sLeft + sRight); return sLeft + sRight; } public static int byteToInt(byte[] id) { int result = 0; for (int k=3; k>=0; k--) { int iZiffer = (int)(id[k]); result = result * 256 + (iZiffer<0?iZiffer+256:iZiffer); } return result; } public static byte[] rebuffering(byte[] buffer, int iStart, int len) { byte[] id = new byte[len]; for (int i=0; i=0; k--) { int iZiffer = (int)(id[k]); result = (short)(result * 256 + (iZiffer<0?iZiffer+256:iZiffer)); } return result; } public void writingValue_1(String path) { try { PrintWriter putItBack = null; // we still have to write the data if (!onlySummary) { putItBack = new PrintWriter(new FileWriter(path + ".txt")); putItBack.println(sWholeText); putItBack.close(); } } catch(IOException e) { } return; } public void writingValue_2(String path) { try { PrintWriter putItBack = null; // we still have to write the data putItBack = new PrintWriter(new FileWriter(path + "_summaries.txt")); putItBack.println(sSummariesText); putItBack.close(); } catch(IOException e) { } return; } }