diff --git a/CumulusMX/Cumulus.cs b/CumulusMX/Cumulus.cs index 7eeef3cd..b296bdc3 100644 --- a/CumulusMX/Cumulus.cs +++ b/CumulusMX/Cumulus.cs @@ -2085,79 +2085,92 @@ internal async void UpdateAwekas(DateTime timestamp) try { - HttpResponseMessage response = await AwekashttpClient.GetAsync(url); - var responseBodyAsText = await response.Content.ReadAsStringAsync(); - LogDebugMessage("AWEKAS Response code = " + response.StatusCode); - LogDataMessage("AWEKAS: Response text = " + responseBodyAsText); - //var respJson = JsonConvert.DeserializeObject(responseBodyAsText); - var respJson = JsonSerializer.DeserializeFromString(responseBodyAsText); - - // Check the status response - if (respJson.status == 2) - LogMessage("AWEKAS: Data stored OK"); - else if (respJson.status == 1) - { - LogMessage("AWEKAS: Data PARIALLY stored"); - // TODO: Check errors and disabled - } - else if (respJson.status == 0) // Authenication error or rate limited + using (HttpResponseMessage response = await AwekashttpClient.GetAsync(url)) { - if (respJson.minuploadtime > 0 && respJson.authentication == 0) + var responseBodyAsText = await response.Content.ReadAsStringAsync(); + LogDebugMessage("AWEKAS Response code = " + response.StatusCode); + LogDataMessage("AWEKAS: Response text = " + responseBodyAsText); + //var respJson = JsonConvert.DeserializeObject(responseBodyAsText); + var respJson = JsonSerializer.DeserializeFromString(responseBodyAsText); + + // Check the status response + if (respJson.status == 2) + LogMessage("AWEKAS: Data stored OK"); + else if (respJson.status == 1) { - LogMessage("AWEKAS: Authentication error"); - if (AWEKAS.Interval < 60) - { - AWEKAS.RateLimited = true; - AWEKAS.OriginalInterval = AWEKAS.Interval; - AWEKAS.Interval = 60; - AwekasTimer.Enabled = false; - AWEKAS.SynchronisedUpdate = true; - LogMessage("AWEKAS: Temporarily increasing AWEKAS upload interval to 60 seconds due to authenication error"); - } + LogMessage("AWEKAS: Data PARIALLY stored"); + // TODO: Check errors and disabled } - else if (respJson.minuploadtime == 0) + else if (respJson.status == 0) // Authenication error or rate limited { - LogMessage("AWEKAS: Too many requests, rate limited"); - if (AWEKAS.Interval < 60) + if (respJson.minuploadtime > 0 && respJson.authentication == 0) + { + LogMessage("AWEKAS: Authentication error"); + if (AWEKAS.Interval < 300) + { + AWEKAS.RateLimited = true; + AWEKAS.OriginalInterval = AWEKAS.Interval; + AWEKAS.Interval = 300; + AwekasTimer.Enabled = false; + AWEKAS.SynchronisedUpdate = true; + LogMessage("AWEKAS: Temporarily increasing AWEKAS upload interval to 300 seconds due to authenication error"); + } + } + else if (respJson.minuploadtime == 0) { - AWEKAS.RateLimited = true; - AWEKAS.OriginalInterval = AWEKAS.Interval; - AWEKAS.Interval = 60; - AwekasTimer.Enabled = false; - AWEKAS.SynchronisedUpdate = true; - LogMessage("AWEKAS: Temporarily increasing AWEKAS upload interval to 60 seconds due to rate limit"); + LogMessage("AWEKAS: Too many requests, rate limited"); + // AWEKAS PLus allows minimum of 60 second updates, try that first + if (!AWEKAS.RateLimited && AWEKAS.Interval < 60) + { + AWEKAS.OriginalInterval = AWEKAS.Interval; + AWEKAS.RateLimited = true; + AWEKAS.Interval = 60; + AwekasTimer.Enabled = false; + AWEKAS.SynchronisedUpdate = true; + LogMessage("AWEKAS: Temporarily increasing AWEKAS upload interval to 60 seconds due to rate limit"); + } + // AWEKAS normal allows minimum of 300 second updates, revert to that + else + { + AWEKAS.RateLimited = true; + AWEKAS.Interval = 300; + AwekasTimer.Interval = AWEKAS.Interval * 1000; + AwekasTimer.Enabled = !AWEKAS.SynchronisedUpdate; + AWEKAS.SynchronisedUpdate = AWEKAS.Interval % 60 == 0; + LogMessage("AWEKAS: Temporarily increasing AWEKAS upload interval to 300 seconds due to rate limit"); + } + } + else + { + LogMessage("AWEKAS: Unknown error"); } } - else + + // check the min upload time is greater than our upload time + if (respJson.status > 0 && respJson.minuploadtime > AWEKAS.OriginalInterval) { - LogMessage("AWEKAS: Unknown error"); + LogMessage($"AWEKAS: The minimum upload time to AWEKAS for your station is {respJson.minuploadtime} sec, Cumulus is configured for {AWEKAS.OriginalInterval} sec, increasing Cumulus interval to match AWEKAS"); + AWEKAS.Interval = respJson.minuploadtime; + WriteIniFile(); + AwekasTimer.Interval = AWEKAS.Interval * 1000; + AWEKAS.SynchronisedUpdate = AWEKAS.Interval % 60 == 0; + AwekasTimer.Enabled = !AWEKAS.SynchronisedUpdate; + // we got a successful upload, and reset the interval, so clear the rate limited values + AWEKAS.OriginalInterval = AWEKAS.Interval; + AWEKAS.RateLimited = false; + } + else if (AWEKAS.RateLimited && respJson.status > 0) + { + // We are currently rate limited, it could have been a transient thing because + // we just got a valid response, and our interval is >= the minimum allowed. + // So we just undo the limit, and resume as before + LogMessage($"AWEKAS: Removing temporary increase in upload interval to 60 secs, resuming uploads every {AWEKAS.OriginalInterval} secs"); + AWEKAS.Interval = AWEKAS.OriginalInterval; + AwekasTimer.Interval = AWEKAS.Interval * 1000; + AWEKAS.SynchronisedUpdate = AWEKAS.Interval % 60 == 0; + AwekasTimer.Enabled = !AWEKAS.SynchronisedUpdate; + AWEKAS.RateLimited = false; } - } - - // check the min upload time is greater than our upload time - if (respJson.status > 0 && respJson.minuploadtime > AWEKAS.OriginalInterval) - { - LogMessage($"AWEKAS: The minimum upload time to AWEKAS for your station is {respJson.minuploadtime} sec, Cumulus is configured for {AWEKAS.OriginalInterval} sec, increasing Cumulus interval to match AWEKAS"); - AWEKAS.Interval = respJson.minuploadtime; - WriteIniFile(); - AwekasTimer.Interval = AWEKAS.Interval * 1000; - AWEKAS.SynchronisedUpdate = AWEKAS.Interval % 60 == 0; - AwekasTimer.Enabled = !AWEKAS.SynchronisedUpdate; - // we got a successful upload, and reset the interval, so clear the rate limited values - AWEKAS.OriginalInterval = AWEKAS.Interval; - AWEKAS.RateLimited = false; - } - else if (AWEKAS.RateLimited && respJson.status > 0) - { - // We are currently rate limited, it could have been a transient thing because - // we just got a valid response, and our interval is >= the minimum allowed. - // So we just undo the limit, and resume as before - LogMessage($"AWEKAS: Removing temporary increase in upload interval to 60 secs, resuming uploads every {AWEKAS.OriginalInterval} secs"); - AWEKAS.Interval = AWEKAS.OriginalInterval; - AwekasTimer.Interval = AWEKAS.Interval * 1000; - AWEKAS.SynchronisedUpdate = AWEKAS.Interval % 60 == 0; - AwekasTimer.Enabled = !AWEKAS.SynchronisedUpdate; - AWEKAS.RateLimited = false; } } catch (Exception ex) @@ -2561,11 +2574,6 @@ private void RealtimeFTPUpload(byte cycle) var remoteFile = remotePath + RealtimeFiles[i].RemoteFileName; var localFile = RealtimeFiles[i].LocalPath + RealtimeFiles[i].LocalFileName; - if (RealtimeFiles[i].Create && !string.IsNullOrWhiteSpace(RealtimeFiles[i].TemplateFileName)) - { - ProcessTemplateFile(RealtimeFiles[i].TemplateFileName, localFile, tokenParser); - } - LogFtpMessage($"Realtime[{cycle}]: Uploading - {RealtimeFiles[i].LocalFileName}"); if (Sslftp == FtpProtocols.SFTP) { diff --git a/CumulusMX/InternetSettings.cs b/CumulusMX/InternetSettings.cs index 69161a42..96627424 100644 --- a/CumulusMX/InternetSettings.cs +++ b/CumulusMX/InternetSettings.cs @@ -887,7 +887,7 @@ public string GetInternetAlpacaFormSchema() public string GetExtraWebFilesData() { var json = new StringBuilder(10240); - json.Append("{\"metadata\":[{\"name\":\"local\",\"label\":\"Local Filename\",\"datatype\":\"string\",\"editable\":true},{\"name\":\"remote\",\"label\":\"Remote Filename\",\"datatype\":\"string\",\"editable\":true},{\"name\":\"process\",\"label\":\"Process\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"realtime\",\"label\":\"Realtime\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"ftp\",\"label\":\"FTP\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"utf8\",\"label\":\"UTF-8\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"binary\",\"label\":\"Binary\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"endofday\",\"label\":\"End of day\",\"datatype\":\"boolean\",\"editable\":true}],\"data\":["); + json.Append("{\"metadata\":[{\"name\":\"local\",\"label\":\"Local Filename\",\"datatype\":\"string\",\"editable\":true},{\"name\":\"remote\",\"label\":\"Destination Filename\",\"datatype\":\"string\",\"editable\":true},{\"name\":\"process\",\"label\":\"Process\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"realtime\",\"label\":\"Realtime\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"ftp\",\"label\":\"FTP\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"utf8\",\"label\":\"UTF-8\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"binary\",\"label\":\"Binary\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"endofday\",\"label\":\"End of day\",\"datatype\":\"boolean\",\"editable\":true}],\"data\":["); for (int i = 0; i < Cumulus.numextrafiles; i++) { diff --git a/CumulusMX/NOAA.cs b/CumulusMX/NOAA.cs index f8f51b9b..9dc7270a 100644 --- a/CumulusMX/NOAA.cs +++ b/CumulusMX/NOAA.cs @@ -912,300 +912,330 @@ public List CreateYearlyReport(DateTime thedate) } // Now output everything - output.Clear(); - output.Add($" Annual Climatological Summary for {year}"); - output.Add(""); - output.Add($"Name: {cumulus.NOAAname} City: {cumulus.NOAAcity} State: {cumulus.NOAAstate}"); - string elev; - if (cumulus.AltitudeInFeet) - { - elev = cumulus.Altitude + " ft"; - } - else + try { - elev = cumulus.Altitude + " m"; - } - int latdeg; - int latmin; - int latsec; - DecodeLatLong(Math.Abs(cumulus.Latitude), out latdeg, out latmin, out latsec); - int londeg; - int lonmin; - int lonsec; - DecodeLatLong(Math.Abs(cumulus.Longitude), out londeg, out lonmin, out lonsec); - - var lathem = cumulus.Latitude > 0 ? "N" : "S"; - var lonhem = cumulus.Longitude > 0 ? "E" : "W"; + output.Clear(); + output.Add($" Annual Climatological Summary for {year}"); + output.Add(""); + output.Add($"Name: {cumulus.NOAAname} City: {cumulus.NOAAcity} State: {cumulus.NOAAstate}"); + string elev; + if (cumulus.AltitudeInFeet) + { + elev = cumulus.Altitude + " ft"; + } + else + { + elev = cumulus.Altitude + " m"; + } + int latdeg; + int latmin; + int latsec; + DecodeLatLong(Math.Abs(cumulus.Latitude), out latdeg, out latmin, out latsec); + int londeg; + int lonmin; + int lonsec; + DecodeLatLong(Math.Abs(cumulus.Longitude), out londeg, out lonmin, out lonsec); + + var lathem = cumulus.Latitude > 0 ? "N" : "S"; + var lonhem = cumulus.Longitude > 0 ? "E" : "W"; + + latdeg = Math.Abs(latdeg); + londeg = Math.Abs(londeg); + + output.Add($"Elevation: {elev} Lat: {string.Format("{0} {1,2:D2}° {2,2:D2}' {3,2:D2}\"", lathem, latdeg, latmin, latsec)} Lon: {string.Format("{0} {1,3:D3}° {2,2:D2}' {3,2:D2}\"", lonhem, londeg, lonmin, lonsec)}"); + output.Add(""); + output.Add($" Temperature ({cumulus.Units.TempText}), Heat Base: {cumulus.NOAAheatingthreshold.ToString(cumulus.TempFormat, culture)} Cool Base: {cumulus.NOAAcoolingthreshold.ToString(cumulus.TempFormat, culture)}"); + output.Add(" Dep. Heat Cool Max Max Min Min"); + output.Add(" Mean Mean From Deg Deg >= <= <= <="); + //@ Unsupported function or procedure: 'Format' + output.Add($" YR MO Max Min Mean Norm Days Days Hi Date Low Date{string.Format(culture, "{0,5:F1}{1,5:F1}{2,5:F1}{3,6:F1}", cumulus.NOAAmaxtempcomp1, cumulus.NOAAmaxtempcomp2, cumulus.NOAAmintempcomp1, cumulus.NOAAmintempcomp2)}"); + output.Add("------------------------------------------------------------------------------------"); + for (month = 1; month <= 12; month++) + { + repLine.Clear(); + repLine.Append(string.Format("{0,3}{1,3:D}", twodigityear, month)); + if (MonthList[month].valid) + { + if (MonthList[month].samples == 0) + { + repLine.Append(" ---- ---- ---"); + } + else + { + MonthList[month].meanmaxtemp = MonthList[month].totalmaxtemp / MonthList[month].samples; + MonthList[month].meanmintemp = MonthList[month].totalmintemp / MonthList[month].samples; + MonthList[month].meantemp = MonthList[month].totaltemp / MonthList[month].samples; + repLine.Append(string.Format(culture, "{0,6:F1}{1,6:F1}{2,6:F1}", MonthList[month].meanmaxtemp, MonthList[month].meanmintemp, MonthList[month].meantemp)); + } + if (cumulus.NOAATempNorms[month] < -999) + { + // dummy value for 'departure from norm' + repLine.Append(" 0.0"); + } + else + { + repLine.Append(string.Format(culture, "{0,6:F1}", (MonthList[month].meantemp - cumulus.NOAATempNorms[month]))); + totalnormtemp += cumulus.NOAATempNorms[month]; + normtempsamples++; + } + repLine.Append(string.Format(culture, "{0,6:D}{1,6:D}", Convert.ToInt64(MonthList[month].heatingdegdays), Convert.ToInt64(MonthList[month].coolingdegdays))); + repLine.Append(string.Format(culture, "{0,6:F1}{1,4:D}{2,6:F1}{3,5:D}", MonthList[month].maxtemp, MonthList[month].maxtempday, MonthList[month].mintemp, MonthList[month].mintempday)); + repLine.Append(string.Format(culture, "{0,5:D}{1,5:D}{2,5:D}{3,5:D}", MonthList[month].maxtempcount1, MonthList[month].maxtempcount2, MonthList[month].mintempcount1, MonthList[month].mintempcount2)); + } + output.Add(repLine.ToString()); + } + output.Add("------------------------------------------------------------------------------------"); - latdeg = Math.Abs(latdeg); - londeg = Math.Abs(londeg); + // now do the summary - output.Add($"Elevation: {elev} Lat: {string.Format("{0} {1,2:D2}° {2,2:D2}' {3,2:D2}\"", lathem, latdeg, latmin, latsec)} Lon: {string.Format("{0} {1,3:D3}° {2,2:D2}' {3,2:D2}\"", lonhem, londeg, lonmin, lonsec)}"); - output.Add(""); - output.Add($" Temperature ({cumulus.Units.TempText}), Heat Base: {cumulus.NOAAheatingthreshold.ToString(cumulus.TempFormat, culture)} Cool Base: {cumulus.NOAAcoolingthreshold.ToString(cumulus.TempFormat, culture)}"); - output.Add(" Dep. Heat Cool Max Max Min Min"); - output.Add(" Mean Mean From Deg Deg >= <= <= <="); - //@ Unsupported function or procedure: 'Format' - output.Add($" YR MO Max Min Mean Norm Days Days Hi Date Low Date{string.Format(culture, "{0,5:F1}{1,5:F1}{2,5:F1}{3,6:F1}", cumulus.NOAAmaxtempcomp1, cumulus.NOAAmaxtempcomp2, cumulus.NOAAmintempcomp1, cumulus.NOAAmintempcomp2)}"); - output.Add("------------------------------------------------------------------------------------"); - for (month = 1; month <= 12; month++) - { - repLine.Clear(); - repLine.Append(string.Format("{0,3}{1,3:D}", twodigityear, month)); - if (MonthList[month].valid) + for (m = 1; m < 13; m++) { - if (MonthList[month].samples == 0) + if (!MonthList[m].valid) + continue; + + samples += MonthList[m].samples; + totalmeanmaxtemp += MonthList[m].meanmaxtemp * MonthList[m].samples; + totalmeanmintemp += MonthList[m].meanmintemp * MonthList[m].samples; + totalmeantemp += MonthList[m].meantemp * MonthList[m].samples; + + if (MonthList[m].maxtemp > maxtemp) { - repLine.Append(" ---- ---- ---"); + maxtemp = MonthList[m].maxtemp; + maxtempmonth = m; } + + if (MonthList[m].mintemp < mintemp) + { + mintemp = MonthList[m].mintemp; + mintempmonth = m; + } + + maxtempcount1 += MonthList[m].maxtempcount1; + maxtempcount2 += MonthList[m].maxtempcount2; + mintempcount1 += MonthList[m].mintempcount1; + mintempcount2 += MonthList[m].mintempcount2; + } + + if (samples > 0) + { + repLine.Clear(); + double meanmax = totalmeanmaxtemp / samples; + double meanmin = totalmeanmintemp / samples; + double meantemp = totalmeantemp / samples; + repLine.Append(string.Format(culture, "{0,12:F1}{1,6:F1}{2,6:F1}", meanmax, meanmin, meantemp)); + if (normtempsamples == 0) + // dummy value for "departure from norm" + repLine.Append(" 0.0"); else { - MonthList[month].meanmaxtemp = MonthList[month].totalmaxtemp/MonthList[month].samples; - MonthList[month].meanmintemp = MonthList[month].totalmintemp/MonthList[month].samples; - MonthList[month].meantemp = MonthList[month].totaltemp/MonthList[month].samples; - repLine.Append(string.Format(culture, "{0,6:F1}{1,6:F1}{2,6:F1}", MonthList[month].meanmaxtemp, MonthList[month].meanmintemp, MonthList[month].meantemp)); + repLine.Append(string.Format(culture, "{0,6:F1}", (meantemp - (totalnormtemp / normtempsamples)))); } - if (cumulus.NOAATempNorms[month] < -999) + repLine.Append(string.Format(culture, "{0,6:D}{1,6:D}", (int)(totalheating), (int)(totalcooling))); + if (maxtempmonth == 0) { - // dummy value for 'departure from norm' - repLine.Append(" 0.0"); + repLine.Append(string.Format(culture, "{0,6:F1}{1,4}", maxtemp, "---")); + } + else + { + repLine.Append(string.Format(culture, "{0,6:F1}{1,4}", maxtemp, CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(maxtempmonth))); } + if (mintempmonth == 0) + repLine.Append(string.Format(culture, "{0,6:F1}{1,5}", mintemp, "---")); else { - repLine.Append(string.Format(culture, "{0,6:F1}", (MonthList[month].meantemp - cumulus.NOAATempNorms[month]))); - totalnormtemp += cumulus.NOAATempNorms[month]; - normtempsamples++; + repLine.Append(string.Format(culture, "{0,6:F1}{1,5}", mintemp, CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(mintempmonth))); } - repLine.Append(string.Format(culture, "{0,6:D}{1,6:D}", Convert.ToInt64(MonthList[month].heatingdegdays), Convert.ToInt64(MonthList[month].coolingdegdays))); - repLine.Append(string.Format(culture, "{0,6:F1}{1,4:D}{2,6:F1}{3,5:D}", MonthList[month].maxtemp, MonthList[month].maxtempday, MonthList[month].mintemp, MonthList[month].mintempday)); - repLine.Append(string.Format(culture, "{0,5:D}{1,5:D}{2,5:D}{3,5:D}", MonthList[month].maxtempcount1, MonthList[month].maxtempcount2, MonthList[month].mintempcount1, MonthList[month].mintempcount2)); + repLine.Append(string.Format("{0,5:D}{1,5:D}{2,5:D}{3,5:D}", maxtempcount1, maxtempcount2, mintempcount1, mintempcount2)); + output.Add(repLine.ToString()); } - output.Add(repLine.ToString()); - } - output.Add("------------------------------------------------------------------------------------"); - - // now do the summary - - for (m = 1; m < 13; m++) - { - if (!MonthList[m].valid) - continue; - - samples += MonthList[m].samples; - totalmeanmaxtemp += MonthList[m].meanmaxtemp * MonthList[m].samples; - totalmeanmintemp += MonthList[m].meanmintemp * MonthList[m].samples; - totalmeantemp += MonthList[m].meantemp * MonthList[m].samples; - - if (MonthList[m].maxtemp > maxtemp) + else { - maxtemp = MonthList[m].maxtemp; - maxtempmonth = m; + output.Add(""); } - if (MonthList[m].mintemp < mintemp) + // Rain section header + output.Add(""); + output.Add(" Precipitation (" + cumulus.Units.RainText + ")"); + output.Add(""); + output.Add(" Dep. Max Days of Rain"); + output.Add(" From Obs. >="); + output.Add(" YR MO Total Norm Day Date" + + string.Format("{0,5}{1,5}{2,5}", cumulus.NOAAraincomp1.ToString(cumulus.RainFormat, culture), cumulus.NOAAraincomp2.ToString(cumulus.RainFormat, culture), + cumulus.NOAAraincomp3.ToString(cumulus.RainFormat, culture))); + output.Add("---------------------------------------------"); + + // Rain section details + for (m = 1; m < 13; m++) { - mintemp = MonthList[m].mintemp; - mintempmonth = m; - } + repLine.Clear(); + repLine.Append(string.Format("{0,3}{1,3:D}", twodigityear, m)); - maxtempcount1 += MonthList[m].maxtempcount1; - maxtempcount2 += MonthList[m].maxtempcount2; - mintempcount1 += MonthList[m].mintempcount1; - mintempcount2 += MonthList[m].mintempcount2; - } + if (!MonthList[m].valid) + continue; - if (samples > 0) - { - repLine.Clear(); - double meanmax = totalmeanmaxtemp/samples; - double meanmin = totalmeanmintemp/samples; - double meantemp = totalmeantemp/samples; - repLine.Append(string.Format(culture, "{0,12:F1}{1,6:F1}{2,6:F1}", meanmax, meanmin, meantemp)); - if (normtempsamples == 0) - // dummy value for "departure from norm" - repLine.Append(" 0.0"); - else - { - repLine.Append(string.Format(culture, "{0,6F1}", (meantemp - (totalnormtemp/normtempsamples)))); - } - repLine.Append(string.Format(culture, "{0,6:D}{1,6:D}", (int) (totalheating), (int) (totalcooling))); - if (maxtempmonth == 0) - { - repLine.Append(string.Format(culture, "{0,6:F1}{1,4}", maxtemp, "---")); - } - else - { - repLine.Append(string.Format(culture, "{0,6:F1}{1,4}", maxtemp, CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(maxtempmonth))); - } - if (mintempmonth == 0) - repLine.Append(string.Format(culture, "{0,6:F1}{1,5}", mintemp, "---")); - else - { - repLine.Append(string.Format(culture, "{0,6:F1}{1,5}", mintemp, CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(mintempmonth))); - } - repLine.Append(string.Format("{0,5:D}{1,5:D}{2,5:D}{3,5:D}", maxtempcount1, maxtempcount2, mintempcount1, mintempcount2)); - output.Add(repLine.ToString()); - } - else - { - output.Add(""); - } - - // Rain section header - output.Add(""); - output.Add(" Precipitation (" + cumulus.Units.RainText + ")"); - output.Add(""); - output.Add(" Dep. Max Days of Rain"); - output.Add(" From Obs. >="); - output.Add(" YR MO Total Norm Day Date" + - string.Format("{0,5}{1,5}{2,5}", cumulus.NOAAraincomp1.ToString(cumulus.RainFormat, culture), cumulus.NOAAraincomp2.ToString(cumulus.RainFormat, culture), - cumulus.NOAAraincomp3.ToString(cumulus.RainFormat, culture))); - output.Add("---------------------------------------------"); - - // Rain section details - for (m = 1; m < 13; m++) - { - repLine.Clear(); - repLine.Append(string.Format("{0,3}{1,3:D}", twodigityear, m)); + repLine.Append(string.Format("{0,6}", MonthList[m].totrain.ToString(cumulus.RainFormat, culture))); + totalrain += MonthList[m].totrain; - if (!MonthList[m].valid) - continue; + if (MonthList[m].maxrain > maxrain) + { + maxrain = MonthList[m].maxrain; + maxrainmonth = m; + } - repLine.Append(string.Format("{0,6}", MonthList[m].totrain.ToString(cumulus.RainFormat, culture))); - totalrain += MonthList[m].totrain; + if (cumulus.NOAARainNorms[m] < -999) + // dummy value for "departure from norm" + repLine.Append(" 0.0"); + else + { + repLine.Append(string.Format("{0,6}", (MonthList[m].totrain - cumulus.NOAARainNorms[m]).ToString(cumulus.RainFormat, culture))); + totalnormrain += cumulus.NOAARainNorms[m]; + } - if (MonthList[m].maxrain > maxrain) - { - maxrain = MonthList[m].maxrain; - maxrainmonth = m; - } + repLine.Append(string.Format("{0,6}", MonthList[m].maxrain.ToString(cumulus.RainFormat, culture))); + repLine.Append(string.Format("{0,4:D}", MonthList[m].maxrainday)); + repLine.Append(string.Format("{0,6:D}{1,5:D}{2,5:D}", MonthList[m].raincount1, MonthList[m].raincount2, MonthList[m].raincount3)); - if (cumulus.NOAARainNorms[m] < -999) - // dummy value for "departure from norm" - repLine.Append(" 0.0"); - else - { - repLine.Append(string.Format("{0,6}", (MonthList[m].totrain - cumulus.NOAARainNorms[m]).ToString(cumulus.RainFormat, culture))); - totalnormrain += cumulus.NOAARainNorms[m]; + raincount1 += MonthList[m].raincount1; + raincount2 += MonthList[m].raincount2; + raincount3 += MonthList[m].raincount3; + { + output.Add(repLine.ToString()); + } } - repLine.Append(string.Format("{0,6}", MonthList[m].maxrain.ToString(cumulus.RainFormat, culture))); - repLine.Append(string.Format("{0,4:D}", MonthList[m].maxrainday)); - repLine.Append(string.Format("{0,6:D}{1,5:D}{2,5:D}", MonthList[m].raincount1, MonthList[m].raincount2, MonthList[m].raincount3)); + output.Add("---------------------------------------------"); - raincount1 += MonthList[m].raincount1; - raincount2 += MonthList[m].raincount2; - raincount3 += MonthList[m].raincount3; + // rain summary + if (samples > 0) { - output.Add(repLine.ToString()); - } - } + repLine.Clear(); + repLine.Append(string.Format("{0,12}", totalrain.ToString(cumulus.RainFormat, culture))); - output.Add("---------------------------------------------"); + if (totalnormrain == 0) + { + // dummy value for "departure from norm" + repLine.Append(" 0.0"); + } + else + { + repLine.Append(string.Format("{0,6}", (totalrain - totalnormrain).ToString(cumulus.RainFormat, culture))); + } - // rain summary - if (samples > 0) - { - repLine.Clear(); - repLine.Append(string.Format("{0,12}", totalrain.ToString(cumulus.RainFormat, culture))); + repLine.Append(string.Format("{0,6}", maxrain.ToString(cumulus.RainFormat, culture))); + if (maxrainmonth == 0) + { + repLine.Append(string.Format("{0,5}", "---")); + } + else + { + repLine.Append(string.Format("{0,5}", CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(maxrainmonth))); + } - if (totalnormrain == 0) - { - // dummy value for "departure from norm" - repLine.Append(" 0.0"); - } - else - { - repLine.Append(string.Format("{0,6}", (totalrain - totalnormrain).ToString(cumulus.RainFormat, culture))); - } + repLine.Append(string.Format("{0,5:D}{1,5:D}{2,5:D}", raincount1, raincount2, raincount3)); - repLine.Append(string.Format("{0,6}", maxrain.ToString(cumulus.RainFormat, culture))); - if (maxrainmonth == 0) - { - repLine.Append(string.Format("{0,5}", "---")); + output.Add(repLine.ToString()); } else { - repLine.Append(string.Format("{0,5}", CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(maxrainmonth))); + output.Add(""); } - repLine.Append(string.Format("{0,5:D}{1,5:D}{2,5:D}", raincount1, raincount2, raincount3)); - - output.Add(repLine.ToString()); - } - else - { output.Add(""); - } - - output.Add(""); - output.Add($" Wind Speed ({cumulus.Units.WindText})"); - output.Add(" Dom"); - output.Add(" YR MO Avg. Hi Date Dir"); - output.Add("------------------------------"); - - // Wind section details - for (m = 1; m < 13; m++) - { - repLine.Clear(); - repLine.Append(string.Format("{0,3}{1,3:D}", twodigityear, m)); + output.Add($" Wind Speed ({cumulus.Units.WindText})"); + output.Add(" Dom"); + output.Add(" YR MO Avg. Hi Date Dir"); + output.Add("------------------------------"); - if (MonthList[m].valid) + // Wind section details + for (m = 1; m < 13; m++) { - // calculate average wind speed - MonthList[m].avgwindspeed = GetAverageWindSpeed(m, year, out domdir); - MonthList[m].winddomdir = domdir; - if (MonthList[m].avgwindspeed < 0) - { - // no valid average - repLine.Append(" ----"); - } - else + try { - // String.Format the average into the display line - repLine.Append(string.Format(culture, "{0,6:F1}", MonthList[m].avgwindspeed)); - totalavgwind += MonthList[m].avgwindspeed * MonthList[m].samples; - avgwindcount += MonthList[m].samples; - } + repLine.Clear(); + repLine.Append(string.Format("{0,3}{1,3:D}", twodigityear, m)); - // String.Format the high wind speed and dominant direction into the display line - repLine.Append(string.Format(culture, "{0,6:F1}{1,5:D}", MonthList[m].highwindspeed, MonthList[m].highwindday)); - repLine.Append(string.Format("{0,6}", CompassPoint(MonthList[m].winddomdir))); + if (MonthList[m].valid) + { + // calculate average wind speed + MonthList[m].avgwindspeed = GetAverageWindSpeed(m, year, out domdir); + MonthList[m].winddomdir = domdir; + if (MonthList[m].avgwindspeed < 0) + { + // no valid average + repLine.Append(" ----"); + } + else + { + // String.Format the average into the display line + repLine.Append(string.Format(culture, "{0,6:F1}", MonthList[m].avgwindspeed)); + totalavgwind += MonthList[m].avgwindspeed * MonthList[m].samples; + avgwindcount += MonthList[m].samples; + } + + // String.Format the high wind speed and dominant direction into the display line + repLine.Append(string.Format(culture, "{0,6:F1}{1,5:D}", MonthList[m].highwindspeed, MonthList[m].highwindday)); + repLine.Append(string.Format("{0,6}", CompassPoint(MonthList[m].winddomdir))); + + // check for highest annual wind speed + if (MonthList[m].highwindspeed > highwind) + { + highwind = MonthList[m].highwindspeed; + highwindmonth = m; + } - // check for highest annual wind speed - if (MonthList[m].highwindspeed > highwind) + // increment the total wind vectors for the annual calculation + totalwinddirX += (MonthList[m].avgwindspeed * Math.Sin(Trig.DegToRad(domdir))) * MonthList[m].samples; + totalwinddirY += (MonthList[m].avgwindspeed * Math.Cos(Trig.DegToRad(domdir))) * MonthList[m].samples; + } + output.Add(repLine.ToString()); + } + catch (Exception e) { - highwind = MonthList[m].highwindspeed; - highwindmonth = m; + cumulus.LogMessage($"CreateYearlyReport: Error creating wind section: {e.Message}"); + cumulus.LogDebugMessage("CreateYearlyReport: Last line generated was..."); + cumulus.LogDebugMessage($"CreateYearlyReport: \"{repLine}\""); + throw; } - - // increment the total wind vectors for the annual calculation - totalwinddirX += (MonthList[m].avgwindspeed*Math.Sin(Trig.DegToRad(domdir))) * MonthList[m].samples; - totalwinddirY += (MonthList[m].avgwindspeed*Math.Cos(Trig.DegToRad(domdir))) * MonthList[m].samples; } - output.Add(repLine.ToString()); - } - output.Add("------------------------------"); + output.Add("------------------------------"); + } + catch (Exception e) + { + cumulus.LogMessage($"CreateYearlyReport: Error creating the report: {e.Message}"); + cumulus.LogDebugMessage("CreateYearlyReport: Output generated so far was..."); + cumulus.LogDebugMessage(string.Join("\n",output)); + throw; + } // wind section summary - if (samples <= 0) - return output; + try + { + if (samples <= 0) + return output; - repLine.Clear(); - if (avgwindcount == 0) - repLine.Append(" ----"); - else - repLine.Append(string.Format(culture, "{0,12:F1}", totalavgwind / avgwindcount)); + repLine.Clear(); + if (avgwindcount == 0) + repLine.Append(" ----"); + else + repLine.Append(string.Format(culture, "{0,12:F1}", totalavgwind / avgwindcount)); - repLine.Append(string.Format(culture, "{0,6:F1}", highwind)); - if (highwindmonth == 0) - { - repLine.Append(string.Format("{0,5}", "---")); + repLine.Append(string.Format(culture, "{0,6:F1}", highwind)); + if (highwindmonth == 0) + { + repLine.Append(string.Format("{0,5}", "---")); + } + else + { + repLine.Append(string.Format("{0,5}", CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(highwindmonth))); + } } - else + catch (Exception e) { - repLine.Append(string.Format("{0,5}", CultureInfo.CurrentCulture.DateTimeFormat.GetAbbreviatedMonthName(highwindmonth))); + cumulus.LogMessage($"CreateYearlyReport: Error creating wind summary: {e.Message}"); + cumulus.LogDebugMessage("CreateYearlyReport: Last line generated was..."); + cumulus.LogDebugMessage($"CreateYearlyReport: \"{repLine}\""); + throw; } try @@ -1216,7 +1246,6 @@ public List CreateYearlyReport(DateTime thedate) domdir = 360; } catch (Exception ex) - { cumulus.LogMessage("Error in NOAA dominant wind direction calculation: " + ex.Message); domdir = 0; diff --git a/CumulusMX/NOAAReports.cs b/CumulusMX/NOAAReports.cs index 2179e3ed..e0d57710 100644 --- a/CumulusMX/NOAAReports.cs +++ b/CumulusMX/NOAAReports.cs @@ -27,14 +27,21 @@ public List GenerateNoaaYearReport(int year) cumulus.LogMessage("Creating NOAA yearly report"); report = noaa.CreateYearlyReport(noaats); - // If not using UTF, then we have to convert the character set - var utf8WithoutBom = new System.Text.UTF8Encoding(false); - var encoding = cumulus.NOAAUseUTF8 ? utf8WithoutBom : System.Text.Encoding.GetEncoding("iso-8859-1"); - var reportName = noaats.ToString(cumulus.NOAAYearFileFormat); - noaafile = cumulus.ReportPath + reportName; - cumulus.LogMessage("Saving yearly NOAA report as " + noaafile); - File.WriteAllLines(noaafile, report, encoding); - + try + { + // If not using UTF, then we have to convert the character set + var utf8WithoutBom = new System.Text.UTF8Encoding(false); + var encoding = cumulus.NOAAUseUTF8 ? utf8WithoutBom : System.Text.Encoding.GetEncoding("iso-8859-1"); + var reportName = noaats.ToString(cumulus.NOAAYearFileFormat); + noaafile = cumulus.ReportPath + reportName; + cumulus.LogMessage("Saving yearly NOAA report as " + noaafile); + File.WriteAllLines(noaafile, report, encoding); + } + catch (Exception e) + { + cumulus.LogMessage($"Error creating NOAA yearly report: {e.Message}"); + throw; + } return report; } @@ -45,29 +52,38 @@ public List GenerateNoaaMonthReport(int year, int month) cumulus.LogMessage("Creating NOAA monthly report"); var report = noaa.CreateMonthlyReport(noaats); - // If not using UTF, then we have to convert the character set - var utf8WithoutBom = new System.Text.UTF8Encoding(false); - var encoding = cumulus.NOAAUseUTF8 ? utf8WithoutBom : System.Text.Encoding.GetEncoding("iso-8859-1"); - var reportName = noaats.ToString(cumulus.NOAAMonthFileFormat); - noaafile = cumulus.ReportPath + reportName; - cumulus.LogMessage("Saving monthly NOAA report as " + noaafile); - File.WriteAllLines(noaafile, report, encoding); - + var reportName = String.Empty; + try + { + // If not using UTF, then we have to convert the character set + var utf8WithoutBom = new System.Text.UTF8Encoding(false); + var encoding = cumulus.NOAAUseUTF8 ? utf8WithoutBom : System.Text.Encoding.GetEncoding("iso-8859-1"); + reportName = noaats.ToString(cumulus.NOAAMonthFileFormat); + noaafile = cumulus.ReportPath + reportName; + cumulus.LogMessage("Saving monthly NOAA report as " + noaafile); + File.WriteAllLines(noaafile, report, encoding); + } + catch (Exception e) + { + cumulus.LogMessage($"Error creating NOAA yearly report '{reportName}': {e.Message}"); + throw; + } return report; } public List GetNoaaYearReport(int year) { DateTime noaats = new DateTime(year, 1, 1); - + var reportName = String.Empty; try { - var reportName = noaats.ToString(cumulus.NOAAYearFileFormat); + reportName = noaats.ToString(cumulus.NOAAYearFileFormat); noaafile = cumulus.ReportPath + reportName; report = File.Exists(noaafile) ? new List(File.ReadAllLines(noaafile)) : new List { "That report does not exist" }; } - catch + catch (Exception e) { + cumulus.LogMessage($"Error getting NOAA yearly report '{reportName}': {e.Message}"); report = new List { "Something went wrong!" }; } return report; @@ -76,16 +92,17 @@ public List GetNoaaYearReport(int year) public List GetNoaaMonthReport(int year, int month) { DateTime noaats = new DateTime(year, month, 1); - + var reportName = String.Empty; try { - var reportName = noaats.ToString(cumulus.NOAAMonthFileFormat); + reportName = noaats.ToString(cumulus.NOAAMonthFileFormat); noaafile = cumulus.ReportPath + reportName; var encoding = cumulus.NOAAUseUTF8 ? Encoding.GetEncoding("utf-8") : Encoding.GetEncoding("iso-8859-1"); report = File.Exists(noaafile) ? new List (File.ReadAllLines(noaafile, encoding)) : new List { "That report does not exist" }; } - catch + catch (Exception e) { + cumulus.LogMessage($"Error getting NOAA monthly report '{reportName}': {e.Message}"); report = new List { "Something went wrong!" }; } return report; diff --git a/CumulusMX/Properties/AssemblyInfo.cs b/CumulusMX/Properties/AssemblyInfo.cs index 7dc91d11..12651415 100644 --- a/CumulusMX/Properties/AssemblyInfo.cs +++ b/CumulusMX/Properties/AssemblyInfo.cs @@ -6,7 +6,7 @@ // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("Cumulus MX")] -[assembly: AssemblyDescription("Build 3116")] +[assembly: AssemblyDescription("Build 3117")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Cumulus MX")] @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.10.1.3116")] -[assembly: AssemblyFileVersion("3.10.1.3116")] +[assembly: AssemblyVersion("3.10.2.3117")] +[assembly: AssemblyFileVersion("3.10.2.3117")] diff --git a/CumulusMX/StationSettings.cs b/CumulusMX/StationSettings.cs index 88503de6..0b457351 100644 --- a/CumulusMX/StationSettings.cs +++ b/CumulusMX/StationSettings.cs @@ -617,6 +617,12 @@ internal string UpdateStationConfig(IHttpContext context) // Display Options try { + // bug catch incase user has the old JSON config files that do not work. + if (settings.DisplayOptions.windrosepoints == 0) + settings.DisplayOptions.windrosepoints = 8; + else if (settings.DisplayOptions.windrosepoints == 1) + settings.DisplayOptions.windrosepoints = 16; + cumulus.NumWindRosePoints = settings.DisplayOptions.windrosepoints; cumulus.WindRoseAngle = 360.0 / cumulus.NumWindRosePoints; cumulus.DisplayOptions.UseApparent = settings.DisplayOptions.useapparent; diff --git a/Updates.txt b/Updates.txt index 1e075de7..d2686f3b 100644 --- a/Updates.txt +++ b/Updates.txt @@ -1,9 +1,28 @@ +3.10.2 - b3117 +—————————————— +- Fix: Improve the AWEKAS fall back for upload interval to go right back to 5 minutes in two stages +- Fix: Occasional corrupt files output that have processed web tags in them +- Fix: Error creating the NOAA Year report for some people +- Fix: Missing station location on gauges.htm web site page + +- New: Default website now removes the "Current Conditions" element if the value is blank +- New: Default web site now auto updates the index.htm and today.htm pages every minute + +- Change: The current conditions is now HTML encoded in case it contains illegal characters + +- Updated default web site files + \web\websitedataT.json + \webfiles\index.htm + \webfiles\gauges.htm + \webfiles\js\setpagedata.js + + + 3.10.1 - b3116 —————————————— - Fix: Bug in temperature conversions introduced in v3.10.0 - 3.10.0 - b3115 —————————————— - Fix: Catch error creating System Uptime counter on Windows