diff --git a/CumulusMX/Alarm.cs b/CumulusMX/Alarm.cs index c9d351d7..44cdc759 100644 --- a/CumulusMX/Alarm.cs +++ b/CumulusMX/Alarm.cs @@ -1,13 +1,16 @@ using System; +using System.Runtime.Serialization; using System.Threading.Tasks; namespace CumulusMX { public class Alarm { - public Cumulus cumulus { get; set; } + public readonly Cumulus cumulus; - public string Name { get; } + public string Id { get; } + + public string Name { get; set; } public virtual bool Enabled { get => enabled; @@ -51,16 +54,18 @@ public bool Triggered public string LastMessage { get; set; } public int TriggerThreshold { get; set; } - AlarmTypes type; + private readonly AlarmTypes type; private protected bool enabled; bool triggered; int triggerCount = 0; DateTime triggeredTime; - public Alarm(string AlarmName, AlarmTypes AlarmType) + public Alarm(string id, AlarmTypes AlarmType, Cumulus cumul, string units = null) { - Name = AlarmName; + Id = id; + cumulus = cumul; type = AlarmType; + Units = units; } public void CheckAlarm(double value) @@ -90,7 +95,7 @@ private void doTriggered(bool value) // If we were not set before, so we need to send an email? if (!triggered) { - cumulus.LogMessage($"Alarm ({Name}): Triggered, value = {Value}"); + cumulus.LogMessage($"Alarm ({Name}): Triggered, value = {value}, threshold = {Value}" + (string.IsNullOrEmpty(LastMessage) ? "" : $", Message = {LastMessage}")); if (Email && cumulus.SmtpOptions.Enabled && cumulus.emailer != null) { @@ -150,7 +155,7 @@ private void doTriggered(bool value) // We are latching, but the latch period has expired, clear the trigger triggered = false; triggerCount = 0; - cumulus.LogMessage($"Alarm ({Name}): Trigger cleared"); + cumulus.LogMessage($"Alarm ({Name}): Trigger cleared, value = {value}"); } } else @@ -158,7 +163,7 @@ private void doTriggered(bool value) // No latch, just clear the trigger triggered = false; triggerCount = 0; - cumulus.LogMessage($"Alarm ({Name}): Trigger cleared"); + cumulus.LogMessage($"Alarm ({Name}): Trigger cleared, value = {value}"); } } } @@ -167,8 +172,16 @@ private void doTriggered(bool value) public class AlarmChange : Alarm { - public AlarmChange(string AlarmName) : base(AlarmName, AlarmTypes.Change) + public string IdUp { get; } + public string IdDown { get; } + + public string NameUp { get; set; } + public string NameDown { get; set; } + + public AlarmChange(string idUp, string idDwn, Cumulus cumul, string units = null) : base("", AlarmTypes.Change, cumul, units) { + IdUp = idUp; + IdDown = idDwn; } public override bool Enabled @@ -260,7 +273,7 @@ private void doUpTriggered(bool value) // If we were not set before, so we need to send an email etc? if (!upTriggered) { - cumulus.LogMessage($"Alarm ({Name}): Up triggered, value = {Value}"); + cumulus.LogMessage($"Alarm ({NameUp}): Up triggered, value = {value}, threshold = {Value}" + (string.IsNullOrEmpty(LastMessage) ? "" : $", Message = {LastMessage}")); if (Email && cumulus.SmtpOptions.Enabled && cumulus.emailer != null) { @@ -274,7 +287,7 @@ private void doUpTriggered(bool value) // delay for 0, 60, 120 seconds System.Threading.Thread.Sleep(i * 60000); - cumulus.LogMessage($"Alarm ({Name}): Sending email - attempt {i + 1}"); + cumulus.LogMessage($"Alarm ({NameUp}): Sending email - attempt {i + 1}"); if (await cumulus.emailer.SendEmail(cumulus.AlarmDestEmail, cumulus.AlarmFromEmail, cumulus.Trans.AlarmEmailSubject, msg, cumulus.AlarmEmailHtml, cumulus.AlarmEmailUseBcc)) { @@ -292,12 +305,12 @@ private void doUpTriggered(bool value) var parser = new TokenParser(cumulus.TokenParserOnToken); parser.InputText = ActionParams; var args = parser.ToStringFromString(); - cumulus.LogMessage($"Alarm ({Name}): Starting external program: '{Action}', with parameters: {args}"); + cumulus.LogMessage($"Alarm ({NameUp}): Starting external program: '{Action}', with parameters: {args}"); Utils.RunExternalTask(Action, args, false); } catch (Exception ex) { - cumulus.LogErrorMessage($"Alarm: Error executing external program '{Action}': {ex.Message}"); + cumulus.LogErrorMessage($"Alarm ({NameUp}): Error executing external program '{Action}': {ex.Message}"); } } } @@ -315,14 +328,14 @@ private void doUpTriggered(bool value) { // We are latching, but the latch period has expired, clear the trigger upTriggered = false; - cumulus.LogMessage($"Alarm ({Name}): Up trigger cleared"); + cumulus.LogMessage($"Alarm ({NameUp}): Up trigger cleared, value = {value}"); } } else { // No latch, just clear the trigger upTriggered = false; - cumulus.LogMessage($"Alarm ({Name}): Up trigger cleared"); + cumulus.LogMessage($"Alarm ({NameUp}): Up trigger cleared, value = {value}"); } } } @@ -334,7 +347,7 @@ private void doDownTriggered(bool value) // If we were not set before, so we need to send an email? if (!downTriggered && Enabled) { - cumulus.LogMessage($"Alarm ({Name}): Down triggered, value = {Value}"); + cumulus.LogMessage($"Alarm ({NameDown}): Down triggered, value = {value}, threshold = {Value}" + (string.IsNullOrEmpty(LastMessage) ? "" : $", Message = {LastMessage}")); if (Email && cumulus.SmtpOptions.Enabled && cumulus.emailer != null) { @@ -348,7 +361,7 @@ private void doDownTriggered(bool value) // delay for 0, 60, 120 seconds System.Threading.Thread.Sleep(i * 60000); - cumulus.LogMessage($"Alarm ({Name}): Sending email - attempt {i + 1}"); + cumulus.LogMessage($"Alarm ({NameDown}): Sending email - attempt {i + 1}"); if (await cumulus.emailer.SendEmail(cumulus.AlarmDestEmail, cumulus.AlarmFromEmail, cumulus.Trans.AlarmEmailSubject, msg, cumulus.AlarmEmailHtml, cumulus.AlarmEmailUseBcc)) { @@ -366,12 +379,12 @@ private void doDownTriggered(bool value) var parser = new TokenParser(cumulus.TokenParserOnToken); parser.InputText = ActionParams; var args = parser.ToStringFromString(); - cumulus.LogMessage($"Alarm ({Name}): Starting external program: '{Action}', with parameters: {args}"); + cumulus.LogMessage($"Alarm ({NameDown}): Starting external program: '{Action}', with parameters: {args}"); Utils.RunExternalTask(Action, args, false); } catch (Exception ex) { - cumulus.LogErrorMessage($"Alarm: Error executing external program '{Action}': {ex.Message}"); + cumulus.LogErrorMessage($"Alarm ({NameDown}): Error executing external program '{Action}': {ex.Message}"); } } } @@ -389,14 +402,14 @@ private void doDownTriggered(bool value) { // We are latching, but the latch period has expired, clear the trigger downTriggered = false; - cumulus.LogMessage($"Alarm ({Name}): Down trigger cleared"); + cumulus.LogMessage($"Alarm ({NameDown}): Down trigger cleared, value = {value}"); } } else { // No latch, just clear the trigger downTriggered = false; - cumulus.LogMessage($"Alarm ({Name}): Down trigger cleared"); + cumulus.LogMessage($"Alarm ({NameDown}): Down trigger cleared, value = {value}"); } } } @@ -412,4 +425,18 @@ public enum AlarmTypes Change, Trigger } + + [DataContract] + public class DashboardAlarms + { + public DashboardAlarms(string Id, bool Triggered) + { + id = Id; + triggered = Triggered; + } + [DataMember] + public string id { get; set; } + [DataMember] + public bool triggered { get; set; } + } } diff --git a/CumulusMX/AlarmSettings.cs b/CumulusMX/AlarmSettings.cs index 2861cb10..096031c6 100644 --- a/CumulusMX/AlarmSettings.cs +++ b/CumulusMX/AlarmSettings.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net; @@ -312,153 +313,225 @@ public string GetAlarmSettings() public string GetAlarmInfo() { - //var InvC = new CultureInfo(""); + var alarms = new List(); - var data = new JsonAlarmInfoData() - { - tempBelow = new JsonAlarmInfo() + if (cumulus.LowTempAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.LowTempAlarm.Enabled, + Id = cumulus.LowTempAlarm.Id, + Name = cumulus.LowTempAlarm.Name, SoundEnabled = cumulus.LowTempAlarm.Sound, Sound = cumulus.LowTempAlarm.SoundFile, Notify = cumulus.LowTempAlarm.Notify - }, - tempAbove = new JsonAlarmInfo() + }); + if (cumulus.HighTempAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.HighTempAlarm.Enabled, + Id = cumulus.HighTempAlarm.Id, + Name = cumulus.HighTempAlarm.Name, SoundEnabled = cumulus.HighTempAlarm.Sound, Sound = cumulus.HighTempAlarm.SoundFile, Notify = cumulus.HighTempAlarm.Notify - }, - tempChange = new JsonAlarmInfo() + }); + if (cumulus.TempChangeAlarm.Enabled) + { + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.TempChangeAlarm.Enabled, + Id = cumulus.TempChangeAlarm.IdUp, + Name = cumulus.TempChangeAlarm.NameUp, SoundEnabled = cumulus.TempChangeAlarm.Sound, Sound = cumulus.TempChangeAlarm.SoundFile, Notify = cumulus.TempChangeAlarm.Notify - }, - pressBelow = new JsonAlarmInfo() + }); + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.LowPressAlarm.Enabled, + Id = cumulus.TempChangeAlarm.IdDown, + Name = cumulus.TempChangeAlarm.NameDown, + SoundEnabled = cumulus.TempChangeAlarm.Sound, + Sound = cumulus.TempChangeAlarm.SoundFile, + Notify = cumulus.TempChangeAlarm.Notify + }); + } + if (cumulus.LowPressAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() + { + Id = cumulus.LowPressAlarm.Id, + Name = cumulus.LowPressAlarm.Name, SoundEnabled = cumulus.LowPressAlarm.Sound, Sound = cumulus.LowPressAlarm.SoundFile, Notify = cumulus.LowPressAlarm.Notify - }, - pressAbove = new JsonAlarmInfo() + }); + if (cumulus.HighPressAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.HighPressAlarm.Enabled, + Id = cumulus.HighPressAlarm.Id, + Name = cumulus.HighPressAlarm.Name, SoundEnabled = cumulus.HighPressAlarm.Sound, Sound = cumulus.HighPressAlarm.SoundFile, Notify = cumulus.HighPressAlarm.Notify - }, - pressChange = new JsonAlarmInfo() + }); + if (cumulus.PressChangeAlarm.Enabled) + { + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.PressChangeAlarm.Enabled, + Id = cumulus.PressChangeAlarm.IdUp, + Name = cumulus.PressChangeAlarm.NameUp, SoundEnabled = cumulus.PressChangeAlarm.Sound, Sound = cumulus.PressChangeAlarm.SoundFile, Notify = cumulus.PressChangeAlarm.Notify - }, - rainAbove = new JsonAlarmInfo() + }); + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.HighRainTodayAlarm.Enabled, + Id = cumulus.PressChangeAlarm.IdDown, + Name = cumulus.PressChangeAlarm.NameDown, + SoundEnabled = cumulus.PressChangeAlarm.Sound, + Sound = cumulus.PressChangeAlarm.SoundFile, + Notify = cumulus.PressChangeAlarm.Notify + }); + } + if (cumulus.HighRainTodayAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() + { + Id = cumulus.HighRainTodayAlarm.Id, + Name = cumulus.HighRainTodayAlarm.Name, SoundEnabled = cumulus.HighRainTodayAlarm.Sound, Sound = cumulus.HighRainTodayAlarm.SoundFile, Notify = cumulus.HighRainTodayAlarm.Notify - }, - rainRateAbove = new JsonAlarmInfo() + }); + if (cumulus.HighRainRateAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.HighRainRateAlarm.Enabled, + Id = cumulus.HighRainRateAlarm.Id, + Name = cumulus.HighRainRateAlarm.Name, SoundEnabled = cumulus.HighRainRateAlarm.Sound, Sound = cumulus.HighRainRateAlarm.SoundFile, Notify = cumulus.HighRainRateAlarm.Notify - }, - isRaining = new JsonAlarmInfo() + }); + if (cumulus.IsRainingAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.IsRainingAlarm.Enabled, + Id = cumulus.IsRainingAlarm.Id, + Name = cumulus.IsRainingAlarm.Name, SoundEnabled = cumulus.IsRainingAlarm.Sound, Sound = cumulus.IsRainingAlarm.SoundFile, Notify = cumulus.IsRainingAlarm.Notify - }, - gustAbove = new JsonAlarmInfo() + }); + if (cumulus.HighGustAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.HighGustAlarm.Enabled, + Id = cumulus.HighGustAlarm.Id, + Name = cumulus.HighGustAlarm.Name, SoundEnabled = cumulus.HighGustAlarm.Sound, Sound = cumulus.HighGustAlarm.SoundFile, Notify = cumulus.HighGustAlarm.Notify - }, - windAbove = new JsonAlarmInfo() + }); + if (cumulus.HighWindAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.HighWindAlarm.Enabled, + Id = cumulus.HighWindAlarm.Id, + Name = cumulus.HighWindAlarm.Name, SoundEnabled = cumulus.HighWindAlarm.Sound, Sound = cumulus.HighWindAlarm.SoundFile, Notify = cumulus.HighWindAlarm.Notify - }, - contactLost = new JsonAlarmInfo() + }); + if (cumulus.SensorAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.SensorAlarm.Enabled, + Id = cumulus.SensorAlarm.Id, + Name = cumulus.SensorAlarm.Name, SoundEnabled = cumulus.SensorAlarm.Sound, Sound = cumulus.SensorAlarm.SoundFile, Notify = cumulus.SensorAlarm.Notify - }, - newRecord = new JsonAlarmInfo() + }); + if (cumulus.NewRecordAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.NewRecordAlarm.Enabled, + Id = cumulus.NewRecordAlarm.Id, + Name = cumulus.NewRecordAlarm.Name, SoundEnabled = cumulus.NewRecordAlarm.Sound, Sound = cumulus.NewRecordAlarm.SoundFile, Notify = cumulus.NewRecordAlarm.Notify - }, - dataStopped = new JsonAlarmInfo() + }); + if (cumulus.DataStoppedAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.DataStoppedAlarm.Enabled, + Id = cumulus.DataStoppedAlarm.Id, + Name = cumulus.DataStoppedAlarm.Name, SoundEnabled = cumulus.DataStoppedAlarm.Sound, Sound = cumulus.DataStoppedAlarm.SoundFile, Notify = cumulus.DataStoppedAlarm.Notify - }, - batteryLow = new JsonAlarmInfo() + }); + if (cumulus.BatteryLowAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.BatteryLowAlarm.Enabled, + Id = cumulus.BatteryLowAlarm.Id, + Name = cumulus.BatteryLowAlarm.Name, SoundEnabled = cumulus.BatteryLowAlarm.Sound, Sound = cumulus.BatteryLowAlarm.SoundFile, Notify = cumulus.BatteryLowAlarm.Notify - }, - spike = new JsonAlarmInfo() + }); + if (cumulus.SpikeAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.SpikeAlarm.Enabled, + Id = cumulus.SpikeAlarm.Id, + Name = cumulus.SpikeAlarm.Name, SoundEnabled = cumulus.SpikeAlarm.Sound, Sound = cumulus.SpikeAlarm.SoundFile, Notify = cumulus.SpikeAlarm.Notify - }, - upgrade = new JsonAlarmInfo() + }); + if (cumulus.UpgradeAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.UpgradeAlarm.Enabled, + Id = cumulus.UpgradeAlarm.Id, + Name = cumulus.UpgradeAlarm.Name, SoundEnabled = cumulus.UpgradeAlarm.Sound, Sound = cumulus.UpgradeAlarm.SoundFile, Notify = cumulus.UpgradeAlarm.Notify - }, - httpUpload = new JsonAlarmInfo() + }); + if (cumulus.ThirdPartyAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.ThirdPartyAlarm.Enabled, + Id = cumulus.ThirdPartyAlarm.Id, + Name = cumulus.ThirdPartyAlarm.Name, SoundEnabled = cumulus.ThirdPartyAlarm.Sound, Sound = cumulus.ThirdPartyAlarm.SoundFile, Notify = cumulus.ThirdPartyAlarm.Notify - }, - mySqlUpload = new JsonAlarmInfo() + }); + if (cumulus.MySqlUploadAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.MySqlUploadAlarm.Enabled, + Id = cumulus.MySqlUploadAlarm.Id, + Name = cumulus.MySqlUploadAlarm.Name, SoundEnabled = cumulus.MySqlUploadAlarm.Sound, Sound = cumulus.MySqlUploadAlarm.SoundFile, Notify = cumulus.MySqlUploadAlarm.Notify - }, - ftpUpload = new JsonAlarmInfo() + }); + if (cumulus.FtpAlarm.Enabled) + alarms.Add(new JsonAlarmInfo() { - Enabled = cumulus.FtpAlarm.Enabled, + Id = cumulus.FtpAlarm.Id, + Name = cumulus.FtpAlarm.Name, SoundEnabled = cumulus.FtpAlarm.Sound, Sound = cumulus.FtpAlarm.SoundFile, Notify = cumulus.FtpAlarm.Notify + }); + + for (var i = 0; i < cumulus.UserAlarms.Count; i++) + { + if (cumulus.UserAlarms[i].Enabled) + { + alarms.Add(new JsonAlarmInfo() + { + Id = "AlarmUser" + i, + Name = cumulus.UserAlarms[i].Name, + SoundEnabled = false, + Sound = "", + Notify = false + }); ; } - }; + } - return data.ToJson(); + return alarms.ToJson(); } @@ -881,39 +954,17 @@ public class JsonAlarmValues public string ActionParams { get; set; } } - public class JsonAlarmInfoData - { - public JsonAlarmInfo tempBelow { get; set; } - public JsonAlarmInfo tempAbove { get; set; } - public JsonAlarmInfo tempChange { get; set; } - public JsonAlarmInfo pressBelow { get; set; } - public JsonAlarmInfo pressAbove { get; set; } - public JsonAlarmInfo pressChange { get; set; } - public JsonAlarmInfo rainAbove { get; set; } - public JsonAlarmInfo rainRateAbove { get; set; } - public JsonAlarmInfo gustAbove { get; set; } - public JsonAlarmInfo windAbove { get; set; } - public JsonAlarmInfo newRecord { get; set; } - public JsonAlarmInfo contactLost { get; set; } - public JsonAlarmInfo dataStopped { get; set; } - public JsonAlarmInfo batteryLow { get; set; } - public JsonAlarmInfo spike { get; set; } - public JsonAlarmInfo upgrade { get; set; } - public JsonAlarmInfo httpUpload { get; set; } - public JsonAlarmInfo mySqlUpload { get; set; } - public JsonAlarmInfo isRaining { get; set; } - public JsonAlarmInfo ftpUpload { get; set; } - } - public class JsonAlarmInfo { - public bool Enabled { get; set; } + public string Id { get; set; } + public string Name { get; set; } public bool SoundEnabled { get; set; } public string Sound { get; set; } public bool Notify { get; set; } } + public class JsonAlarmEmail { public string fromEmail { get; set; } diff --git a/CumulusMX/AlarmUserSettings.cs b/CumulusMX/AlarmUserSettings.cs new file mode 100644 index 00000000..a30ab052 --- /dev/null +++ b/CumulusMX/AlarmUserSettings.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; + +using EmbedIO; + +using ServiceStack; + + +namespace CumulusMX +{ + internal class AlarmUserSettings + { + private readonly Cumulus cumulus; + + public AlarmUserSettings(Cumulus cumulus) + { + this.cumulus = cumulus; + } + + public string GetAlpacaFormData() + { + + var settings = new Settings() + { + accessible = cumulus.ProgramOptions.EnableAccessibility, + alarms = cumulus.UserAlarms + }; + + return settings.ToJson(); + } + + public string UpdateConfig(IHttpContext context) + { + string json = ""; + Settings settings; + try + { + var data = new StreamReader(context.Request.InputStream).ReadToEnd(); + + // Start at char 5 to skip the "json:" prefix + json = WebUtility.UrlDecode(data.Substring(5)); + + // de-serialize it to the settings structure + settings = json.FromJson(); + } + catch (Exception ex) + { + var msg = "Error de-serializing User Alarm Settings JSON: " + ex.Message; + cumulus.LogErrorMessage(msg); + cumulus.LogDebugMessage("User Alarm Data: " + json); + context.Response.StatusCode = 500; + return msg; + } + + // process the settings + try + { + cumulus.LogMessage("Updating User Alarm settings"); + + // clear the existing alarms + cumulus.UserAlarms.Clear(); + + for (var i = 0; i < settings.alarms.Count; i++) + { + cumulus.UserAlarms.Add(new AlarmUser(settings.alarms[i].Name, settings.alarms[i].Type, settings.alarms[i].WebTag, cumulus) + { + Enabled = settings.alarms[i].Enabled, + Value = settings.alarms[i].Value, + Email = settings.alarms[i].Email, + EmailMsg = settings.alarms[i].EmailMsg, + Action = settings.alarms[i].Action, + ActionParams = settings.alarms[i].ActionParams, + Latch = settings.alarms[i].Latch, + LatchHours = settings.alarms[i].LatchHours, + Units = settings.alarms[i].Units, + TriggerThreshold = settings.alarms[i].TriggerThreshold + }); + } + + // Save the settings + cumulus.WriteIniFile(); + + context.Response.StatusCode = 200; + } + catch (Exception ex) + { + var msg = "HTTP file: Error processing settings: " + ex.Message; + cumulus.LogErrorMessage(msg); + context.Response.StatusCode = 500; + return msg; + } + return "success"; + } + + private class Settings + { + public bool accessible { get; set; } + public List alarms { get; set; } + } + } +} diff --git a/CumulusMX/AlarmsUser.cs b/CumulusMX/AlarmsUser.cs new file mode 100644 index 00000000..02e7cf03 --- /dev/null +++ b/CumulusMX/AlarmsUser.cs @@ -0,0 +1,211 @@ +using System; +using System.Runtime.Serialization; +using System.Threading.Tasks; + +namespace CumulusMX +{ + public class AlarmUser + { + private readonly Cumulus cumulus; + + public string Name { get; set; } + public virtual bool Enabled + { + get => enabled; + set + { + enabled = value; + + // if we are disabled, clear any existing alarms + if (!value) + { + triggered = false; + triggerCount = 0; + triggeredTime = DateTime.MinValue; + } + } + } + public string WebTag { get; set; } + public double Value { get; set; } + [IgnoreDataMember] + public bool Triggered + { + get => triggered; + set + { + if (enabled && cumulus.NormalRunning) + { + doTriggered(value); + } + } + } + + [IgnoreDataMember] + public DateTime TriggeredTime { get => triggeredTime; } + public bool Email { get; set; } + public string Action { get; set; } + public string ActionParams { get; set; } + public bool Latch { get; set; } + public double LatchHours { get; set; } + public string EmailMsg { get; set; } + public string Units { get; set; } + public int TriggerThreshold { get; set; } + public string Type { + get => type.ToString(); + set + { + switch (value.ToLower()) + { + case "above": + type = AlarmTypes.Above; + break; + case "below": + type = AlarmTypes.Below; + break; + default: + type = AlarmTypes.Above; + break; + } + } + } + + private AlarmTypes type; + private protected bool enabled; + bool triggered; + int triggerCount = 0; + DateTime triggeredTime; + + private readonly TokenParser tokenParser; + private double tagValue; + + public AlarmUser(string AlarmName, string AlarmType, string webTag, Cumulus cuml) + { + Name = AlarmName; + + switch (AlarmType.ToLower()) + { + case "above": + type = AlarmTypes.Above; + break; + case "below": + type = AlarmTypes.Below; + break; + default: + type = AlarmTypes.Above; + break; + } + + cumulus = cuml; + WebTag = webTag; + tokenParser = new TokenParser(cumulus.TokenParserOnToken) + { + InputText = WebTag + }; + } + + public void CheckAlarm() + { + if (enabled && cumulus.NormalRunning) + { + if (double.TryParse(tokenParser.ToStringFromString(), out tagValue)) + { + doTriggered((type == AlarmTypes.Above && tagValue > Value) || (type == AlarmTypes.Below && tagValue < Value)); + } + else + { + cumulus.LogErrorMessage($"User Alarm ({Name}): Error parsing web tag value: {WebTag}"); + } + } + } + + public void ClearAlarm() + { + if (Latch && triggered && DateTime.Now > triggeredTime.AddHours(LatchHours)) + { + doTriggered(false); + } + } + + private void doTriggered(bool value) + { + if (value) + { + triggerCount++; + triggeredTime = DateTime.Now; + + // do we have a threshold value + if (triggerCount >= TriggerThreshold) + { + // If we were not set before, so we need to send an email? + if (!triggered) + { + cumulus.LogMessage($"User Alarm ({Name}): Triggered, value = {tagValue}"); + + if (Email && cumulus.SmtpOptions.Enabled && cumulus.emailer != null) + { + // Construct the message - preamble, plus values + var msg = cumulus.Trans.AlarmEmailPreamble + "\r\n" + string.Format(EmailMsg, tagValue); + _ = Task.Run(async () => + { + // try to send the email 3 times + for (int i = 0; i < 3; i++) + { + // delay for 0, 60, 120 seconds + System.Threading.Thread.Sleep(i * 60000); + + cumulus.LogMessage($"User Alarm ({Name}): Sending email - attempt {i + 1}"); + + if (await cumulus.emailer.SendEmail(cumulus.AlarmDestEmail, cumulus.AlarmFromEmail, cumulus.Trans.AlarmEmailSubject, msg, cumulus.AlarmEmailHtml, cumulus.AlarmEmailUseBcc)) + { + break; + } + } + }); + } + + if (!string.IsNullOrEmpty(Action)) + { + try + { + // Prepare the process to run + var parser = new TokenParser(cumulus.TokenParserOnToken); + parser.InputText = ActionParams; + var args = parser.ToStringFromString(); + cumulus.LogMessage($"User Alarm ({Name}): Starting external program: '{Action}', with parameters: {args}"); + Utils.RunExternalTask(Action, args, false); + } + catch (Exception ex) + { + cumulus.LogErrorMessage($"User Alarm ({Name}): Error executing external program '{Action}': {ex.Message}"); + } + } + } + + // record the state + triggered = true; + } + } + else if (triggered) + { + // If the trigger is cleared, check if we should be latching the value + if (Latch) + { + if (DateTime.Now > TriggeredTime.AddHours(LatchHours)) + { + // We are latching, but the latch period has expired, clear the trigger + triggered = false; + triggerCount = 0; + cumulus.LogMessage($"User Alarm ({Name}): Trigger cleared, value = {tagValue}"); + } + } + else + { + // No latch, just clear the trigger + triggered = false; + triggerCount = 0; + cumulus.LogMessage($"User Alarm ({Name}): Trigger cleared, value = {tagValue}"); + } + } + } + } +} diff --git a/CumulusMX/Api.cs b/CumulusMX/Api.cs index a48b40e2..64b564e4 100644 --- a/CumulusMX/Api.cs +++ b/CumulusMX/Api.cs @@ -24,12 +24,14 @@ public static class Api public static CalibrationSettings calibrationSettings; public static NOAASettings noaaSettings; public static MysqlSettings mySqlSettings; + public static MqttSettings mqttSettings; public static CustomLogs customLogs; internal static HttpFiles httpFiles; public static Wizard wizard; internal static LangSettings langSettings; internal static DisplaySettings displaySettings; internal static AlarmSettings alarmSettings; + internal static AlarmUserSettings alarmUserSettings; internal static DataEditor dataEditor; internal static ApiTagProcessor tagProcessor; internal static HttpStationWund stationWund; @@ -1156,6 +1158,9 @@ public async Task SettingsGet(string req) case "alarms.json": await writer.WriteAsync(alarmSettings.GetAlarmSettings()); break; + case "useralarms.json": + await writer.WriteAsync(alarmUserSettings.GetAlpacaFormData()); + break; case "wizard.json": await writer.WriteAsync(wizard.GetAlpacaFormData()); break; @@ -1171,6 +1176,9 @@ public async Task SettingsGet(string req) case "httpfiles.json": await writer.WriteAsync(httpFiles.GetAlpacaFormData()); break; + case "mqttdata.json": + await writer.WriteAsync(mqttSettings.GetAlpacaFormData()); + break; default: Response.StatusCode = 404; break; @@ -1248,6 +1256,9 @@ public async Task SettingsSet(string req) case "updatealarmconfig.json": await writer.WriteAsync(alarmSettings.UpdateAlarmSettings(HttpContext)); break; + case "updateuseralarms.json": + await writer.WriteAsync(alarmUserSettings.UpdateConfig(HttpContext)); + break; case "testemail.json": await writer.WriteAsync(alarmSettings.TestEmail(HttpContext)); break; @@ -1269,6 +1280,9 @@ public async Task SettingsSet(string req) case "updatehttpfiles.json": await writer.WriteAsync(httpFiles.UpdateConfig(HttpContext)); break; + case "updatemqttconfig.json": + await writer.WriteAsync(mqttSettings.UpdateConfig(HttpContext)); + break; default: Response.StatusCode = 404; break; @@ -1400,7 +1414,7 @@ public async Task GenReports(string req) public class HttpStation : WebApiController { [Route(HttpVerbs.Post, "/{req}")] - public async Task PostTags(string req) + public async Task PostStation(string req) { try { @@ -1592,6 +1606,9 @@ public async Task PostUtilsData(string req) case "ftpnow.json": await writer.WriteAsync(stationSettings.UploadNow(HttpContext)); break; + case "clearerrorlog.json": + await writer.WriteAsync(cumulus.ClearErrorLog()); + break; default: Response.StatusCode = 404; break; @@ -1636,6 +1653,9 @@ public async Task InfoGet(string req) case "alarms.json": await writer.WriteAsync(alarmSettings.GetAlarmInfo()); break; + case "units.json": + await writer.WriteAsync(Station.GetUnits()); + break; default: Response.StatusCode = 404; break; diff --git a/CumulusMX/ApiTagProcessor.cs b/CumulusMX/ApiTagProcessor.cs index e7fdb555..9f1c6455 100644 --- a/CumulusMX/ApiTagProcessor.cs +++ b/CumulusMX/ApiTagProcessor.cs @@ -87,9 +87,11 @@ public string ProcessText(IHttpRequest request) #if DEBUG cumulus.LogDataMessage($"API tag: Source = {request.RemoteEndPoint} Input string = {data}"); #endif - var tokenParser = new TokenParser(cumulus.TokenParserOnToken); - tokenParser.Encoding = new UTF8Encoding(false); - tokenParser.InputText = data; + var tokenParser = new TokenParser(cumulus.TokenParserOnToken) + { + Encoding = new UTF8Encoding(false), + InputText = data + }; var output = tokenParser.ToStringFromString(); #if DEBUG diff --git a/CumulusMX/CalibrationSettings.cs b/CumulusMX/CalibrationSettings.cs index 07015436..4603beca 100644 --- a/CumulusMX/CalibrationSettings.cs +++ b/CumulusMX/CalibrationSettings.cs @@ -132,9 +132,9 @@ public string GetAlpacaFormData() offset = cumulus.Calib.Press.Offset, multiplier = cumulus.Calib.Press.Mult, multiplier2 = cumulus.Calib.Press.Mult2, - spike = cumulus.Spike.PressDiff, - limitmax = cumulus.Limit.PressHigh, - limitmin = cumulus.Limit.PressLow + spike = Math.Round(cumulus.Spike.PressDiff, cumulus.PressDPlaces), + limitmax = Math.Round(cumulus.Limit.PressHigh, cumulus.PressDPlaces), + limitmin = Math.Round(cumulus.Limit.PressLow, cumulus.PressDPlaces) }; var temp = new JsonCalibrationSettings() @@ -142,9 +142,9 @@ public string GetAlpacaFormData() offset = cumulus.Calib.Temp.Offset, multiplier = cumulus.Calib.Temp.Mult, multiplier2 = cumulus.Calib.Temp.Mult2, - spike = cumulus.Spike.TempDiff, - limitmax = cumulus.Limit.TempHigh, - limitmin = cumulus.Limit.TempLow, + spike = Math.Round(cumulus.Spike.TempDiff, cumulus.TempDPlaces), + limitmax = Math.Round(cumulus.Limit.TempHigh, cumulus.TempDPlaces), + limitmin = Math.Round(cumulus.Limit.TempLow, cumulus.TempDPlaces), }; var tempin = new JsonCalibrationSettings() @@ -152,7 +152,7 @@ public string GetAlpacaFormData() offset = cumulus.Calib.InTemp.Offset, multiplier = cumulus.Calib.InTemp.Mult, multiplier2 = cumulus.Calib.InTemp.Mult2, - spike = cumulus.Spike.InTempDiff + spike = Math.Round(cumulus.Spike.InTempDiff, cumulus.TempDPlaces) }; var hum = new JsonCalibrationSettings() @@ -175,15 +175,15 @@ public string GetAlpacaFormData() { multiplier = cumulus.Calib.WindSpeed.Mult, multiplier2 = cumulus.Calib.WindSpeed.Mult2, - spike = cumulus.Spike.WindDiff + spike = Math.Round(cumulus.Spike.WindDiff, cumulus.WindAvgDPlaces) }; var gust = new JsonCalibrationSettings() { multiplier = cumulus.Calib.WindGust.Mult, multiplier2 = cumulus.Calib.WindGust.Mult2, - spike = cumulus.Spike.GustDiff, - limitmax = cumulus.Limit.WindHigh + spike = Math.Round(cumulus.Spike.GustDiff, cumulus.WindDPlaces), + limitmax = Math.Round(cumulus.Limit.WindHigh, cumulus.WindDPlaces) }; var winddir = new JsonCalibrationSettings() @@ -194,8 +194,8 @@ public string GetAlpacaFormData() var rain = new JsonCalibrationSettings() { multiplier = cumulus.Calib.Rain.Mult, - spikehour = cumulus.Spike.MaxHourlyRain, - spikerate = cumulus.Spike.MaxRainRate + spikehour = Math.Round(cumulus.Spike.MaxHourlyRain, cumulus.RainDPlaces), + spikerate = Math.Round(cumulus.Spike.MaxRainRate, cumulus.RainDPlaces) }; var solar = new JsonCalibrationSettings() @@ -214,14 +214,14 @@ public string GetAlpacaFormData() var wetbulb = new JsonCalibrationSettings() { - offset = cumulus.Calib.WetBulb.Offset, + offset = Math.Round(cumulus.Calib.WetBulb.Offset, cumulus.TempDPlaces), multiplier = cumulus.Calib.WetBulb.Mult, multiplier2 = cumulus.Calib.WetBulb.Mult2 }; var dewpt = new JsonCalibrationSettings() { - limitmax = cumulus.Limit.DewHigh + limitmax = Math.Round(cumulus.Limit.DewHigh, cumulus.TempDPlaces) }; var data = new JsonCalibrationSettingsData() diff --git a/CumulusMX/ConvertUnits.cs b/CumulusMX/ConvertUnits.cs new file mode 100644 index 00000000..cdfa38ca --- /dev/null +++ b/CumulusMX/ConvertUnits.cs @@ -0,0 +1,418 @@ + +namespace CumulusMX +{ + internal static class ConvertUnits + { + /// + /// Convert temp supplied in C to units in use + /// + /// Temp in C + /// Temp in configured units + public static double TempCToUser(double value) + { + if (Program.cumulus.Units.Temp == 1) + { + return MeteoLib.CToF(value); + } + else + { + // C + return value; + } + } + + /// + /// Convert temp supplied in F to units in use + /// + /// Temp in F + /// Temp in configured units + public static double TempFToUser(double value) + { + if (Program.cumulus.Units.Temp == 0) + { + return MeteoLib.FtoC(value); + } + else + { + // F + return value; + } + } + + /// + /// Convert temp supplied in user units to C + /// + /// Temp in configured units + /// Temp in C + public static double UserTempToC(double value) + { + if (Program.cumulus.Units.Temp == 1) + { + return MeteoLib.FtoC(value); + } + else + { + // C + return value; + } + } + + /// + /// Convert temp supplied in user units to F + /// + /// Temp in configured units + /// Temp in F + public static double UserTempToF(double value) + { + if (Program.cumulus.Units.Temp == 1) + { + return value; + } + else + { + // C + return MeteoLib.CToF(value); + } + } + + /// + /// Converts wind supplied in m/s to user units + /// + /// Wind in m/s + /// Wind in configured units + public static double WindMSToUser(double value) + { + switch (Program.cumulus.Units.Wind) + { + case 0: + return value; + case 1: + return value * 2.23693629; + case 2: + return value * 3.6; + case 3: + return value * 1.94384449; + default: + return 0; + } + } + + /// + /// Converts wind supplied in mph to user units + /// + /// Wind in mph + /// Wind in configured units + public static double WindMPHToUser(double value) + { + switch (Program.cumulus.Units.Wind) + { + case 0: + return value * 0.44704; + case 1: + return value; + case 2: + return value * 1.60934; + case 3: + return value * 0.868976; + default: + return 0; + } + } + + /// + /// Converts wind in user units to m/s + /// + /// + /// + public static double WindToMS(double value) + { + switch (Program.cumulus.Units.Wind) + { + case 0: + return value; + case 1: + return value / 2.23693629; + case 2: + return value / 3.6F; + case 3: + return value / 1.94384449; + default: + return 0; + } + } + + /// + /// Converts value in kilometres to distance unit based on users configured wind units + /// + /// + /// Wind in configured units + public static double KmtoUserUnits(double val) + { + switch (Program.cumulus.Units.Wind) + { + case 0: // m/s + case 2: // km/h + return val; + case 1: // mph + return val * 0.621371; + case 3: // knots + return val * 0.539957; + } + return val; + } + + /// + /// Converts windrun supplied in user units to km + /// + /// Windrun in configured units + /// Wind in km + public static double WindRunToKm(double value) + { + switch (Program.cumulus.Units.Wind) + { + case 0: // m/s + case 2: // km/h + return value; + case 1: // mph + return value / 0.621371192; + case 3: // knots + return value / 0.539957; + default: + return 0; + } + } + + /// + /// Converts windrun supplied in user units to miles + /// + /// Windrun in configured units + /// Wind in mi + public static double WindRunToMi(double value) + { + switch (Program.cumulus.Units.Wind) + { + case 0: // m/s + case 2: // km/h + return value * 0.621371192; + case 1: // mph + return value; + case 3: // knots + return value / 0.8689762; + default: + return 0; + } + } + + /// + /// Converts windrun supplied in user units to nautical miles + /// + /// Windrun in configured units + /// Wind in Nm + public static double WindRunToNm(double value) + { + switch (Program.cumulus.Units.Wind) + { + case 0: // m/s + case 2: // km/h + return value * 0.539956803; + case 1: // mph + return value * 0.8689762; + case 3: // knots + return value; + default: + return 0; + } + } + + public static double UserWindToKPH(double wind) // input is in Units.Wind units, convert to km/h + { + switch (Program.cumulus.Units.Wind) + { + case 0: // m/s + return wind * 3.6; + case 1: // mph + return wind * 1.609344; + case 2: // kph + return wind; + case 3: // knots + return wind * 1.852; + default: + return wind; + } + } + + public static double UserWindToMS(double wind) // input is in Units.Wind units, convert to m/s + { + switch (Program.cumulus.Units.Wind) + { + case 0: // m/s + return wind; + case 1: // mph + return wind * 0.44704; + case 2: // kph + return wind * 0.2777778; + case 3: // knots + return wind * 0.5144444; + default: + return wind; + } + } + + public static double UserWindToMPH(double value) + { + switch (Program.cumulus.Units.Wind) + { + case 0: + return value * 2.23693629; + case 1: + return value; + case 2: + return value * 0.621371; + case 3: + return value * 1.15077945; + default: + return 0; + } + } + + public static double UserWindToKnots(double value) + { + switch (Program.cumulus.Units.Wind) + { + case 0: + return value * 1.943844; + case 1: + return value * 0.8689758; + case 2: + return value * 0.5399565; + case 3: + return value; + default: + return 0; + } + } + + + /// + /// Converts rain in mm to units in use + /// + /// Rain in mm + /// Rain in configured units + public static double RainMMToUser(double value) + { + return Program.cumulus.Units.Rain == 1 ? value * 0.0393700787 : value; + } + + /// + /// Converts rain in inches to units in use + /// + /// Rain in mm + /// Rain in configured units + public static double RainINToUser(double value) + { + return Program.cumulus.Units.Rain == 1 ? value : value * 25.4; + } + + /// + /// Converts rain in units in use to mm + /// + /// Rain in configured units + /// Rain in mm + public static double UserRainToMM(double value) + { + return Program.cumulus.Units.Rain == 1 ? value / 0.0393700787 : value; + } + + public static double UserRainToIN(double rain) + { + return Program.cumulus.Units.Rain == 0 ? rain * 0.0393700787 : rain; + } + + + /// + /// Convert pressure in mb to units in use + /// + /// pressure in mb + /// pressure in configured units + public static double PressMBToUser(double value) + { + return Program.cumulus.Units.Press == 2 ? value * 0.0295333727 : value; + } + + /// + /// Convert pressure in inHg to units in use + /// + /// pressure in mb + /// pressure in configured units + public static double PressINHGToUser(double value) + { + return Program.cumulus.Units.Press == 2 ? value : value * 33.8638866667; + } + + /// + /// Convert pressure in units in use to mb + /// + /// pressure in configured units + /// pressure in mb + public static double UserPressToMB(double value) + { + return Program.cumulus.Units.Press == 2 ? value / 0.0295333727 : value; + } + + /// + /// Convert pressure from user units to hPa + /// + /// + /// + public static double UserPressureToHPa(double value) + { + return Program.cumulus.Units.Press == 2 ? value / 0.0295333727 : value; + } + + /// + /// Convert pressure in units in use to inHg + /// + /// pressure in configured units + /// pressure in mb + public static double UserPressToIN(double value) + { + return Program.cumulus.Units.Press == 2 ? value : value * 0.0295333727; + } + + /// + /// Takes speed in user units, returns Bft number + /// + /// + /// + public static int Beaufort(double speed) + { + double windspeedMS = UserWindToMS(speed); + if (windspeedMS < 0.3) + return 0; + else if (windspeedMS < 1.6) + return 1; + else if (windspeedMS < 3.4) + return 2; + else if (windspeedMS < 5.5) + return 3; + else if (windspeedMS < 8.0) + return 4; + else if (windspeedMS < 10.8) + return 5; + else if (windspeedMS < 13.9) + return 6; + else if (windspeedMS < 17.2) + return 7; + else if (windspeedMS < 20.8) + return 8; + else if (windspeedMS < 24.5) + return 9; + else if (windspeedMS < 28.5) + return 10; + else if (windspeedMS < 32.7) + return 11; + else return 12; + } + + } +} diff --git a/CumulusMX/Cumulus.cs b/CumulusMX/Cumulus.cs index fac97b12..feb9e586 100644 --- a/CumulusMX/Cumulus.cs +++ b/CumulusMX/Cumulus.cs @@ -226,7 +226,7 @@ public struct TExtraFiles public const int LogFileRetries = 3; - private readonly WeatherStation station; + private WeatherStation station; internal DavisAirLink airLinkIn; public int airLinkInLsid; @@ -243,7 +243,7 @@ public struct TExtraFiles public PerformanceCounter UpTime; - internal readonly WebTags WebTags; + internal WebTags WebTags; internal Lang Trans = new Lang(); @@ -371,7 +371,7 @@ public struct TExtraFiles public double Altitude; internal int wsPort; - private readonly bool DebuggingEnabled; + private bool DebuggingEnabled; public SerialPort cmprtRG11; public SerialPort cmprt2RG11; @@ -384,14 +384,14 @@ public struct TExtraFiles public string Alltimelogfile; public string MonthlyAlltimeIniFile; public string MonthlyAlltimeLogFile; - private readonly string logFilePath; + private string logFilePath; public string DayFileName; public string YesterdayFile; public string TodayIniFile; public string MonthIniFile; public string YearIniFile; //private readonly string stringsFile; - private readonly string backupPath; + private string backupPath; //private readonly string ExternaldataFile; public string WebTagFile; @@ -487,7 +487,7 @@ public struct TExtraFiles public string WxnowComment = string.Empty; // MQTT settings - public struct MqttSettings + public struct MqttConfig { public string Server; public int Port; @@ -498,10 +498,9 @@ public struct MqttSettings public bool EnableDataUpdate; public string UpdateTemplate; public bool EnableInterval; - public int IntervalTime; public string IntervalTemplate; } - public MqttSettings MQTT; + public MqttConfig MQTT; // NOAA report settings public NOAAconfig NOAAconf = new NOAAconfig(); @@ -522,27 +521,28 @@ public struct MqttSettings public double CPUtemp = -999; // Alarms - public Alarm DataStoppedAlarm = new Alarm("Data Stopped", AlarmTypes.Trigger); - public Alarm BatteryLowAlarm = new Alarm("Battery Low", AlarmTypes.Trigger); - public Alarm SensorAlarm = new Alarm("Sensor Data Stopped", AlarmTypes.Trigger); - public Alarm SpikeAlarm = new Alarm("Data Spike", AlarmTypes.Trigger); - public Alarm HighWindAlarm = new Alarm("High Wind", AlarmTypes.Above); - public Alarm HighGustAlarm = new Alarm("High Gust", AlarmTypes.Above); - public Alarm HighRainRateAlarm = new Alarm("High Rainfall Rate", AlarmTypes.Above); - public Alarm HighRainTodayAlarm = new Alarm("Total Rainfall Today", AlarmTypes.Above); - public AlarmChange PressChangeAlarm = new AlarmChange("Pressure Change"); - public Alarm HighPressAlarm = new Alarm("High Pressure", AlarmTypes.Above); - public Alarm LowPressAlarm = new Alarm("Low Pressure", AlarmTypes.Below); - public AlarmChange TempChangeAlarm = new AlarmChange("Temperature Change"); - public Alarm HighTempAlarm = new Alarm("High Temperature", AlarmTypes.Above); - public Alarm LowTempAlarm = new Alarm("Low Temperature", AlarmTypes.Below); - public Alarm UpgradeAlarm = new Alarm("Upgrade Available", AlarmTypes.Trigger); - public Alarm ThirdPartyAlarm = new Alarm("HTTP Uploads", AlarmTypes.Trigger); - public Alarm MySqlUploadAlarm = new Alarm("MySQL Uploads", AlarmTypes.Trigger); - public Alarm IsRainingAlarm = new Alarm("IsRaining", AlarmTypes.Trigger); - public Alarm NewRecordAlarm = new Alarm("New Record", AlarmTypes.Trigger); - public Alarm FtpAlarm = new Alarm("Web Upload", AlarmTypes.Trigger); - + public Alarm DataStoppedAlarm; + public Alarm BatteryLowAlarm; + public Alarm SensorAlarm; + public Alarm SpikeAlarm; + public Alarm HighWindAlarm; + public Alarm HighGustAlarm; + public Alarm HighRainRateAlarm; + public Alarm HighRainTodayAlarm; + public AlarmChange PressChangeAlarm; + public Alarm HighPressAlarm; + public Alarm LowPressAlarm; + public AlarmChange TempChangeAlarm; + public Alarm HighTempAlarm; + public Alarm LowTempAlarm; + public Alarm UpgradeAlarm; + public Alarm ThirdPartyAlarm; + public Alarm MySqlUploadAlarm; + public Alarm IsRainingAlarm; + public Alarm NewRecordAlarm; + public Alarm FtpAlarm; + + public List UserAlarms = new List(); private const double DEFAULTFCLOWPRESS = 950.0; private const double DEFAULTFCHIGHPRESS = 1050.0; @@ -657,7 +657,7 @@ public struct MqttSettings //private PingReply pingReply; - private readonly SemaphoreSlim uploadCountLimitSemaphoreSlim; + private SemaphoreSlim uploadCountLimitSemaphoreSlim; // Global cancellation token for when CMX is stopping public readonly CancellationTokenSource tokenSource = new CancellationTokenSource(); @@ -666,25 +666,12 @@ public struct MqttSettings private static bool boolWindows; - public Cumulus(int HTTPport, bool DebugEnabled, string startParms) + public Cumulus() { cancellationToken = tokenSource.Token; - var fullVer = Assembly.GetExecutingAssembly().GetName().Version; - Version = $"{fullVer.Major}.{fullVer.Minor}.{fullVer.Build}"; - Build = Assembly.GetExecutingAssembly().GetName().Version.Revision.ToString(); - DirectorySeparator = Path.DirectorySeparatorChar; - AppDir = Directory.GetCurrentDirectory() + DirectorySeparator; - WebTagFile = AppDir + "WebTags.txt"; - - //b3045>, use same port for WS... WS port = HTTPS port - //wsPort = WSport; - wsPort = HTTPport; - - DebuggingEnabled = DebugEnabled; - // Set up the diagnostic tracing loggingfile = RemoveOldDiagsFiles("CMX"); ftpLogfile = RemoveOldDiagsFiles("FTP"); @@ -695,8 +682,22 @@ public Cumulus(int HTTPport, bool DebugEnabled, string startParms) TextWriterTraceListener myTextListener = new TextWriterTraceListener(loggingfile, "MXlog"); Trace.Listeners.Add(myTextListener); Trace.AutoFlush = true; + } - // Read the configuration file + public void Initialise(int HTTPport, bool DebugEnabled, string startParms) + { + var fullVer = Assembly.GetExecutingAssembly().GetName().Version; + Version = $"{fullVer.Major}.{fullVer.Minor}.{fullVer.Build}"; + Build = Assembly.GetExecutingAssembly().GetName().Version.Revision.ToString(); + + AppDir = Directory.GetCurrentDirectory() + DirectorySeparator; + WebTagFile = AppDir + "WebTags.txt"; + + //b3045>, use same port for WS... WS port = HTTPS port + //wsPort = WSport; + wsPort = HTTPport; + + DebuggingEnabled = DebugEnabled; LogMessage(" ========================== Cumulus MX starting =========================="); @@ -1052,6 +1053,28 @@ public Cumulus(int HTTPport, bool DebugEnabled, string startParms) CustomDailyLogSettings[i] = new CustomLogSettings(); } + // initialise the alarms + DataStoppedAlarm = new Alarm("AlarmData", AlarmTypes.Trigger, this); + BatteryLowAlarm = new Alarm("AlarmBattery", AlarmTypes.Trigger, this); + SensorAlarm = new Alarm("AlarmSensor", AlarmTypes.Trigger, this); + SpikeAlarm = new Alarm("AlarmSpike", AlarmTypes.Trigger, this); + HighWindAlarm = new Alarm("AlarmWind", AlarmTypes.Above, this, Units.WindText); + HighGustAlarm = new Alarm("AlarmGust", AlarmTypes.Above, this, Units.WindText); + HighRainRateAlarm = new Alarm("AlarmRainRate", AlarmTypes.Above, this, Units.RainTrendText); + HighRainTodayAlarm = new Alarm("AlarmRain", AlarmTypes.Above, this, Units.RainText); + PressChangeAlarm = new AlarmChange("AlarmPressUp", "AlarmPressDn", this, Units.PressTrendText); + HighPressAlarm = new Alarm("AlarmHighPress", AlarmTypes.Above, this, Units.PressText); + LowPressAlarm = new Alarm("AlarmLowPress", AlarmTypes.Below, this, Units.PressText); + TempChangeAlarm = new AlarmChange("AlarmTempUp", "AlarmTempDn", this, Units.TempTrendText); + HighTempAlarm = new Alarm("AlarmHighTemp", AlarmTypes.Above, this, Units.TempText); + LowTempAlarm = new Alarm("AlarmLowTemp", AlarmTypes.Below, this, Units.TempText); + UpgradeAlarm = new Alarm("AlarmUpgrade", AlarmTypes.Trigger, this); + ThirdPartyAlarm = new Alarm("AlarmHttp", AlarmTypes.Trigger, this); + MySqlUploadAlarm = new Alarm("AlarmMySql", AlarmTypes.Trigger, this); + IsRainingAlarm = new Alarm("AlarmIsRaining", AlarmTypes.Trigger, this); + NewRecordAlarm = new Alarm("AlarmNewRec", AlarmTypes.Trigger, this); + FtpAlarm = new Alarm("AlarmFtp", AlarmTypes.Trigger, this); + ReadIniFile(); // Do we prevent more than one copy of CumulusMX running? @@ -1083,7 +1106,7 @@ public Cumulus(int HTTPport, bool DebugEnabled, string startParms) LogMessage("Daylight saving time name: " + localZone.DaylightName); LogMessage("Daylight saving time? " + localZone.IsDaylightSavingTime(now)); - LogMessage(DateTime.Now.ToString("G")); + LogMessage("Locale date/time format: " + DateTime.Now.ToString("G")); // Do we delay the start of Cumulus MX for a fixed period? if (ProgramOptions.StartupDelaySecs > 0) @@ -1363,46 +1386,18 @@ public Cumulus(int HTTPport, bool DebugEnabled, string startParms) SetupUnitText(); LogMessage($"WindUnit={Units.WindText} RainUnit={Units.RainText} TempUnit={Units.TempText} PressureUnit={Units.PressText}"); - LogMessage($"YTDRain={YTDrain:F3} Year={YTDrainyear}"); + LogMessage($"Manual rainfall: YTDRain={YTDrain:F3}, Correction Year={YTDrainyear}"); LogMessage($"RainDayThreshold={RainDayThreshold:F3}"); - LogMessage($"Roll over hour={RolloverHour}"); + LogMessage($"Roll over hour={RolloverHour:D2}"); + if (RolloverHour != 0) + { + LogMessage("Use 10am in summer =" + Use10amInSummer); + } LogOffsetsMultipliers(); LogPrimaryAqSensor(); - // initialise the alarms - DataStoppedAlarm.cumulus = this; - BatteryLowAlarm.cumulus = this; - SensorAlarm.cumulus = this; - SpikeAlarm.cumulus = this; - HighWindAlarm.cumulus = this; - HighWindAlarm.Units = Units.WindText; - HighGustAlarm.cumulus = this; - HighGustAlarm.Units = Units.WindText; - HighRainRateAlarm.cumulus = this; - HighRainRateAlarm.Units = Units.RainTrendText; - HighRainTodayAlarm.cumulus = this; - HighRainTodayAlarm.Units = Units.RainText; - PressChangeAlarm.cumulus = this; - PressChangeAlarm.Units = Units.PressTrendText; - HighPressAlarm.cumulus = this; - HighPressAlarm.Units = Units.PressText; - LowPressAlarm.cumulus = this; - LowPressAlarm.Units = Units.PressText; - TempChangeAlarm.cumulus = this; - TempChangeAlarm.Units = Units.TempTrendText; - HighTempAlarm.cumulus = this; - HighTempAlarm.Units = Units.TempText; - LowTempAlarm.cumulus = this; - LowTempAlarm.Units = Units.TempText; - UpgradeAlarm.cumulus = this; - ThirdPartyAlarm.cumulus = this; - MySqlUploadAlarm.cumulus = this; - IsRainingAlarm.cumulus = this; - NewRecordAlarm.cumulus = this; - FtpAlarm.cumulus = this; - GetLatestVersion(); LogMessage("Cumulus Starting"); @@ -1453,7 +1448,9 @@ public Cumulus(int HTTPport, bool DebugEnabled, string startParms) Api.calibrationSettings = new CalibrationSettings(this); Api.noaaSettings = new NOAASettings(this); Api.alarmSettings = new AlarmSettings(this); + Api.alarmUserSettings = new AlarmUserSettings(this); Api.mySqlSettings = new MysqlSettings(this); + Api.mqttSettings = new MqttSettings(this); Api.customLogs = new CustomLogs(this); Api.dataEditor = new DataEditor(this); Api.tagProcessor = new ApiTagProcessor(this); @@ -1677,11 +1674,6 @@ public Cumulus(int HTTPport, bool DebugEnabled, string startParms) if (MQTT.EnableDataUpdate || MQTT.EnableInterval) { MqttPublisher.Setup(this); - - if (MQTT.EnableInterval) - { - MQTTTimer.Elapsed += MQTTTimerTick; - } } InitialiseRG11(); @@ -2269,10 +2261,10 @@ private void AwekasTimerTick(object sender, ElapsedEventArgs e) UpdateAwekas(DateTime.Now); } - public void MQTTTimerTick(object sender, ElapsedEventArgs e) + public void MQTTSecondChanged(DateTime now) { - if (!station.DataStopped) - MqttPublisher.UpdateMQTTfeed("Interval"); + if (MQTT.EnableInterval && !station.DataStopped) + MqttPublisher.UpdateMQTTfeed("Interval", now); } /* @@ -4151,28 +4143,42 @@ public string RemoveOldDiagsFiles(string logType) if (logType == "CMX") { - List fileEntries = new List(Directory.GetFiles(directory).Where(f => System.Text.RegularExpressions.Regex.Match(f, @"[\\/]+\d{8}-\d{6}\.txt").Success)); + try + { + List fileEntries = new List(Directory.GetFiles(directory).Where(f => Regex.Match(f, @"[\\/]+\d{8}-\d{6}\.txt").Success)); - fileEntries.Sort(); + fileEntries.Sort(); - while (fileEntries.Count >= maxEntries) + while (fileEntries.Count >= maxEntries) + { + File.Delete(fileEntries.First()); + fileEntries.RemoveAt(0); + } + } + catch (Exception ex) { - File.Delete(fileEntries.First()); - fileEntries.RemoveAt(0); + LogExceptionMessage(ex, "Error removing old MXdiags files"); } filename = $"{directory}{DateTime.Now:yyyyMMdd-HHmmss}.txt"; } else if (logType == "FTP") { - List fileEntries = new List(Directory.GetFiles(directory).Where(f => System.Text.RegularExpressions.Regex.Match(f, @"[\\/]+FTP-\d{8}-\d{6}\.txt").Success)); + try + { + List fileEntries = new List(Directory.GetFiles(directory).Where(f => System.Text.RegularExpressions.Regex.Match(f, @"[\\/]+FTP-\d{8}-\d{6}\.txt").Success)); - fileEntries.Sort(); + fileEntries.Sort(); - while (fileEntries.Count >= maxEntries) + while (fileEntries.Count >= maxEntries) + { + File.Delete(fileEntries.First()); + fileEntries.RemoveAt(0); + } + } + catch (Exception ex) { - File.Delete(fileEntries.First()); - fileEntries.RemoveAt(0); + LogExceptionMessage(ex, "Error removing old FTP log files"); } filename = $"{directory}FTP-{DateTime.Now:yyyyMMdd-HHmmss}.txt"; @@ -4269,14 +4275,23 @@ private void ReadIniFile() // if the culture names match, then we apply the new date separator if change is enabled and it contains a space if (ProgramOptions.Culture.RemoveSpaceFromDateSeparator && CultureInfo.CurrentCulture.DateTimeFormat.DateSeparator.Contains(" ")) { - // get the existing culture - var newCulture = (CultureInfo) CultureInfo.CurrentCulture.Clone(); // change the date separator - newCulture.DateTimeFormat.DateSeparator = CultureInfo.CurrentCulture.DateTimeFormat.DateSeparator.Replace(" ", ""); + var dateSep = CultureInfo.CurrentCulture.DateTimeFormat.DateSeparator.Replace(" ", ""); + var shortDate = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern.Replace(" ", ""); + // set current thread culture - Thread.CurrentThread.CurrentCulture = newCulture; + Thread.CurrentThread.CurrentCulture.DateTimeFormat.DateSeparator = dateSep; + Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern = shortDate; + + Thread.CurrentThread.CurrentUICulture.DateTimeFormat.DateSeparator = dateSep; + Thread.CurrentThread.CurrentUICulture.DateTimeFormat.ShortDatePattern = shortDate; + // set the default culture for other threads - CultureInfo.DefaultThreadCurrentCulture = newCulture; + CultureInfo.DefaultThreadCurrentCulture.DateTimeFormat.DateSeparator = dateSep; + CultureInfo.DefaultThreadCurrentCulture.DateTimeFormat.ShortDatePattern = shortDate; + + CultureInfo.DefaultThreadCurrentUICulture.DateTimeFormat.DateSeparator = dateSep; + CultureInfo.DefaultThreadCurrentUICulture.DateTimeFormat.ShortDatePattern = shortDate; } ProgramOptions.TimeFormat = ini.GetValue("Program", "TimeFormat", "t"); @@ -4538,6 +4553,34 @@ private void ReadIniFile() Spike.MaxHourlyRain = ini.GetValue("Station", "EWmaxHourlyRain", 999.0); Spike.InTempDiff = ini.GetValue("Station", "EWinTempdiff", 999.0); Spike.InHumDiff = ini.GetValue("Station", "EWinHumiditydiff", 999.0); + if (Spike.TempDiff < 999) + { + Spike.TempDiff = ConvertUnits.TempCToUser(Spike.TempDiff); + } + if (Spike.PressDiff < 999) + { + Spike.PressDiff = ConvertUnits.PressMBToUser(Spike.PressDiff); + } + if (Spike.GustDiff < 999) + { + Spike.GustDiff = ConvertUnits.WindMSToUser(Spike.GustDiff); + } + if (Spike.WindDiff < 999) + { + Spike.WindDiff = ConvertUnits.WindMSToUser(Spike.WindDiff); + } + if (Spike.MaxRainRate < 999) + { + Spike.MaxRainRate = ConvertUnits.RainMMToUser(Spike.MaxRainRate); + } + if (Spike.MaxHourlyRain < 999) + { + Spike.MaxHourlyRain = ConvertUnits.RainMMToUser(Spike.MaxHourlyRain); + } + if (Spike.InTempDiff < 999) + { + Spike.InTempDiff = ConvertUnits.TempCToUser(Spike.InTempDiff); + } LCMaxWind = ini.GetValue("Station", "LCMaxWind", 9999); @@ -5225,7 +5268,6 @@ private void ReadIniFile() MQTT.EnableDataUpdate = ini.GetValue("MQTT", "EnableDataUpdate", false); MQTT.UpdateTemplate = ini.GetValue("MQTT", "UpdateTemplate", "DataUpdateTemplate.txt"); MQTT.EnableInterval = ini.GetValue("MQTT", "EnableInterval", false); - MQTT.IntervalTime = ini.GetValue("MQTT", "IntervalTime", 600); // default to 10 minutes MQTT.IntervalTemplate = ini.GetValue("MQTT", "IntervalTemplate", "IntervalTemplate.txt"); LowTempAlarm.Value = ini.GetValue("Alarms", "alarmlowtemp", 0.0); @@ -5510,6 +5552,47 @@ private void ReadIniFile() AlarmEmailHtml = ini.GetValue("Alarms", "UseHTML", false); AlarmEmailUseBcc = ini.GetValue("Alarms", "UseBCC", false); + // User Alarm Settings + for (var i = 0; i < 10; i++) + { + if (ini.ValueExists("UserAlarms", "AlarmName" + i)) + { + var name = ini.GetValue("UserAlarms", "AlarmName" + i, ""); + var tag = ini.GetValue("UserAlarms", "AlarmTag" + i, ""); + var type = ini.GetValue("UserAlarms", "AlarmType" + i, ""); + var value = ini.GetValue("UserAlarms", "AlarmValue" + i, 0.0); + var enabled = ini.GetValue("UserAlarms", "AlarmEnabled" + i, false); + var email = ini.GetValue("UserAlarms", "AlarmEmail" + i, false); + var emailMsg = ini.GetValue("UserAlarms", "AlarmEmailMsg" + i, ""); + var latch = ini.GetValue("UserAlarms", "AlarmLatch" + i, false); + var latchHours = ini.GetValue("UserAlarms", "AlarmLatchHours" + i, 24.0); + var action = ini.GetValue("UserAlarms", "AlarmAction" + i, ""); + var actionParams = ini.GetValue("UserAlarms", "AlarmActionParams" + i, ""); + + if (name != "" && tag != "" && type != "") + { + try + { + UserAlarms.Add(new AlarmUser(name, type, tag, this) + { + Value = value, + Enabled = enabled, + Email = email, + EmailMsg = emailMsg, + Latch = latch, + LatchHours = latchHours, + Action = action, + ActionParams = actionParams + }); + } + catch (Exception ex) + { + LogErrorMessage($"Error loading user alarm {ini.GetValue("UserAlarms", "AlarmName" + i, "")}: {ex.Message}"); + } + } + } + } + Calib.Press.Offset = ini.GetValue("Offsets", "PressOffset", 0.0); Calib.Temp.Offset = ini.GetValue("Offsets", "TempOffset", 0.0); Calib.Hum.Offset = ini.GetValue("Offsets", "HumOffset", 0); @@ -5542,12 +5625,12 @@ private void ReadIniFile() Calib.Solar.Mult2 = ini.GetValue("Offsets", "SolarMult2", 0.0); Calib.UV.Mult2 = ini.GetValue("Offsets", "UVMult2", 0.0); - Limit.TempHigh = ini.GetValue("Limits", "TempHighC", 60.0); - Limit.TempLow = ini.GetValue("Limits", "TempLowC", -60.0); - Limit.DewHigh = ini.GetValue("Limits", "DewHighC", 40.0); - Limit.PressHigh = ini.GetValue("Limits", "PressHighMB", 1090.0); - Limit.PressLow = ini.GetValue("Limits", "PressLowMB", 870.0); - Limit.WindHigh = ini.GetValue("Limits", "WindHighMS", 90.0); + Limit.TempHigh = ConvertUnits.TempCToUser(ini.GetValue("Limits", "TempHighC", 60.0)); + Limit.TempLow = ConvertUnits.TempCToUser(ini.GetValue("Limits", "TempLowC", -60.0)); + Limit.DewHigh = ConvertUnits.TempCToUser(ini.GetValue("Limits", "DewHighC", 40.0)); + Limit.PressHigh = ConvertUnits.PressMBToUser(ini.GetValue("Limits", "PressHighMB", 1090.0)); + Limit.PressLow = ConvertUnits.PressMBToUser(ini.GetValue("Limits", "PressLowMB", 870.0)); + Limit.WindHigh = ConvertUnits.WindMSToUser(ini.GetValue("Limits", "WindHighMS", 90.0)); xapEnabled = ini.GetValue("xAP", "Enabled", false); xapUID = ini.GetValue("xAP", "UID", "4375"); @@ -6115,14 +6198,14 @@ internal void WriteIniFile() ini.SetValue("Station", "EWMaxRainTipDiff", EwOptions.MaxRainTipDiff); ini.SetValue("Station", "EWpressureoffset", EwOptions.PressOffset); - ini.SetValue("Station", "EWtempdiff", Spike.TempDiff); - ini.SetValue("Station", "EWpressurediff", Spike.PressDiff); + ini.SetValue("Station", "EWtempdiff", Spike.TempDiff < 999 ? ConvertUnits.UserTempToC(Spike.TempDiff) : 999.0); + ini.SetValue("Station", "EWpressurediff", Spike.PressDiff < 999 ? ConvertUnits.UserPressToMB(Spike.PressDiff) : 999.00); ini.SetValue("Station", "EWhumiditydiff", Spike.HumidityDiff); - ini.SetValue("Station", "EWgustdiff", Spike.GustDiff); - ini.SetValue("Station", "EWwinddiff", Spike.WindDiff); - ini.SetValue("Station", "EWmaxHourlyRain", Spike.MaxHourlyRain); - ini.SetValue("Station", "EWmaxRainRate", Spike.MaxRainRate); - ini.SetValue("Station", "EWinTempdiff", Spike.InTempDiff); + ini.SetValue("Station", "EWgustdiff", Spike.GustDiff < 999 ? ConvertUnits.UserWindToMS(Spike.GustDiff) : 999.0); + ini.SetValue("Station", "EWwinddiff", Spike.WindDiff < 999 ? ConvertUnits.UserWindToMS(Spike.WindDiff) : 999.0); + ini.SetValue("Station", "EWmaxHourlyRain", Spike.MaxHourlyRain < 999 ? ConvertUnits.UserRainToMM(Spike.MaxHourlyRain) : 999.0); + ini.SetValue("Station", "EWmaxRainRate", Spike.MaxRainRate < 999 ? ConvertUnits.UserRainToMM(Spike.MaxRainRate) : 999.0); + ini.SetValue("Station", "EWinTempdiff", Spike.InTempDiff < 999 ? ConvertUnits.UserTempToC(Spike.InTempDiff) : 999.0); ini.SetValue("Station", "EWinHumiditydiff", Spike.InHumDiff); ini.SetValue("Station", "RainSeasonStart", RainSeasonStart); @@ -6511,7 +6594,6 @@ internal void WriteIniFile() ini.SetValue("MQTT", "EnableDataUpdate", MQTT.EnableDataUpdate); ini.SetValue("MQTT", "UpdateTemplate", MQTT.UpdateTemplate); ini.SetValue("MQTT", "EnableInterval", MQTT.EnableInterval); - ini.SetValue("MQTT", "IntervalTime", MQTT.IntervalTime); ini.SetValue("MQTT", "IntervalTemplate", MQTT.IntervalTemplate); ini.SetValue("Alarms", "alarmlowtemp", LowTempAlarm.Value); @@ -6737,6 +6819,37 @@ internal void WriteIniFile() ini.SetValue("Alarms", "UseHTML", AlarmEmailHtml); ini.SetValue("Alarms", "UseBCC", AlarmEmailUseBcc); + // User Alarms + for (var i = 0; i < UserAlarms.Count(); i++) + { + ini.SetValue("UserAlarms", "AlarmName" + i, UserAlarms[i].Name); + ini.SetValue("UserAlarms", "AlarmTag" + i, UserAlarms[i].WebTag); + ini.SetValue("UserAlarms", "AlarmType" + i, UserAlarms[i].Type); + ini.SetValue("UserAlarms", "AlarmValue" + i, UserAlarms[i].Value); + ini.SetValue("UserAlarms", "AlarmEnabled" + i, UserAlarms[i].Enabled); + ini.SetValue("UserAlarms", "AlarmEmail" + i, UserAlarms[i].Email); + ini.SetValue("UserAlarms", "AlarmEmailMsg" + i, UserAlarms[i].EmailMsg); + ini.SetValue("UserAlarms", "AlarmLatch" + i, UserAlarms[i].Latch); + ini.SetValue("UserAlarms", "AlarmLatchHours" + i, UserAlarms[i].LatchHours); + ini.SetValue("UserAlarms", "AlarmAction" + i, UserAlarms[i].Action); + ini.SetValue("UserAlarms", "AlarmActionParams" + i, UserAlarms[i].ActionParams); + } + // remove any old alarms + for (var i = UserAlarms.Count(); i < 10; i++) + { + ini.DeleteValue("UserAlarms", "AlarmName" + i); + ini.DeleteValue("UserAlarms", "AlarmTag" + i); + ini.DeleteValue("UserAlarms", "AlarmType" + i); + ini.DeleteValue("UserAlarms", "AlarmValue" + i); + ini.DeleteValue("UserAlarms", "AlarmEnabled" + i); + ini.DeleteValue("UserAlarms", "AlarmEmail" + i); + ini.DeleteValue("UserAlarms", "AlarmEmailMsg" + i); + ini.DeleteValue("UserAlarms", "AlarmLatch" + i); + ini.DeleteValue("UserAlarms", "AlarmLatchHours" + i); + ini.DeleteValue("UserAlarms", "AlarmAction" + i); + ini.DeleteValue("UserAlarms", "AlarmActionParams" + i); + } + ini.SetValue("Offsets", "PressOffset", Calib.Press.Offset); ini.SetValue("Offsets", "TempOffset", Calib.Temp.Offset); ini.SetValue("Offsets", "HumOffset", Calib.Hum.Offset); @@ -6770,12 +6883,12 @@ internal void WriteIniFile() ini.SetValue("Offsets", "SolarMult2", Calib.Solar.Mult2); ini.SetValue("Offsets", "UVMult2", Calib.UV.Mult2); - ini.SetValue("Limits", "TempHighC", Limit.TempHigh); - ini.SetValue("Limits", "TempLowC", Limit.TempLow); - ini.SetValue("Limits", "DewHighC", Limit.DewHigh); - ini.SetValue("Limits", "PressHighMB", Limit.PressHigh); - ini.SetValue("Limits", "PressLowMB", Limit.PressLow); - ini.SetValue("Limits", "WindHighMS", Limit.WindHigh); + ini.SetValue("Limits", "TempHighC", ConvertUnits.UserTempToC(Limit.TempHigh)); + ini.SetValue("Limits", "TempLowC", ConvertUnits.UserTempToC(Limit.TempLow)); + ini.SetValue("Limits", "DewHighC", ConvertUnits.UserTempToC(Limit.DewHigh)); + ini.SetValue("Limits", "PressHighMB", ConvertUnits.UserPressToMB(Limit.PressHigh)); + ini.SetValue("Limits", "PressLowMB", ConvertUnits.UserPressToMB(Limit.PressLow)); + ini.SetValue("Limits", "WindHighMS", ConvertUnits.UserWindToMS(Limit.WindHigh)); ini.SetValue("xAP", "Enabled", xapEnabled); ini.SetValue("xAP", "UID", xapUID); @@ -7297,6 +7410,7 @@ private void ReadStringsFile() // alarm emails Trans.AlarmEmailSubject = ini.GetValue("AlarmEmails", "subject", "Cumulus MX Alarm"); Trans.AlarmEmailPreamble = ini.GetValue("AlarmEmails", "preamble", "A Cumulus MX alarm has been triggered."); + HighGustAlarm.EmailMsg = ini.GetValue("AlarmEmails", "windGustAbove", "A wind gust above {0} {1} has occurred."); HighPressAlarm.EmailMsg = ini.GetValue("AlarmEmails", "pressureAbove", "The pressure has risen above {0} {1}."); HighTempAlarm.EmailMsg = ini.GetValue("AlarmEmails", "tempAbove", "The temperature has risen above {0} {1}."); @@ -7320,6 +7434,30 @@ private void ReadStringsFile() NewRecordAlarm.EmailMsg = ini.GetValue("AlarmEmails", "newRecord", "A new all-time record has been set."); FtpAlarm.EmailMsg = ini.GetValue("AlarmEmails", "ftpStopped", "FTP uploads have stopped."); + // alarm names + HighGustAlarm.Name = ini.GetValue("AlarmNames", "windGustAbove", "High Gust"); + HighPressAlarm.Name = ini.GetValue("AlarmNames", "pressureAbove", "High Pressure"); + HighTempAlarm.Name = ini.GetValue("AlarmNames", "tempAbove", "High Temperature"); + LowPressAlarm.Name = ini.GetValue("AlarmNames", "pressBelow", "Low Pressure"); + LowTempAlarm.Name = ini.GetValue("AlarmNames", "tempBelow", "Low Temperature"); + PressChangeAlarm.NameDown = ini.GetValue("AlarmNames", "pressDown", "Pressure Falling"); + PressChangeAlarm.NameUp = ini.GetValue("AlarmNames", "pressUp", "Pressure Rising"); + HighRainTodayAlarm.Name = ini.GetValue("AlarmNames", "rainAbove", "Rainfall Today"); + HighRainRateAlarm.Name = ini.GetValue("AlarmNames", "rainRateAbove", "High Rainfall Rate"); + SensorAlarm.Name = ini.GetValue("AlarmNames", "sensorLost", "Sensor Data Stopped"); + TempChangeAlarm.NameDown = ini.GetValue("AlarmNames", "tempDown", "Temp Falling"); + TempChangeAlarm.NameUp = ini.GetValue("AlarmNames", "tempUp", "Temp Rising"); + HighWindAlarm.Name = ini.GetValue("AlarmNames", "windAbove", "High Wind"); + DataStoppedAlarm.Name = ini.GetValue("AlarmNames", "dataStopped", "Data Stopped"); + BatteryLowAlarm.Name = ini.GetValue("AlarmNames", "batteryLow", "Battery Low"); + SpikeAlarm.Name = ini.GetValue("AlarmNames", "dataSpike", "Data Spike"); + UpgradeAlarm.Name = ini.GetValue("AlarmNames", "upgrade", "Upgrade Available"); + ThirdPartyAlarm.Name = ini.GetValue("AlarmNames", "httpStopped", "HTTP Upload"); + MySqlUploadAlarm.Name = ini.GetValue("AlarmNames", "mySqlStopped", "MySQL Upload"); + IsRainingAlarm.Name = ini.GetValue("AlarmNames", "isRaining", "Is Raining"); + NewRecordAlarm.Name = ini.GetValue("AlarmNames", "newRecord", "New Record"); + FtpAlarm.Name = ini.GetValue("AlarmNames", "ftpStopped", "Web Upload"); + if (!File.Exists("strings.ini")) { WriteStringsFile(); @@ -7485,6 +7623,30 @@ public void WriteStringsFile() ini.SetValue("AlarmEmails", "newRecord", NewRecordAlarm.EmailMsg); ini.SetValue("AlarmEmails", "ftpStopped", FtpAlarm.EmailMsg); + // alarm names + ini.SetValue("AlarmNames", "windGustAbove", HighGustAlarm.Name); + ini.SetValue("AlarmNames", "pressureAbove", HighPressAlarm.Name); + ini.SetValue("AlarmNames", "tempAbove", HighTempAlarm.Name); + ini.SetValue("AlarmNames", "pressBelow", LowPressAlarm.Name); + ini.SetValue("AlarmNames", "tempBelow", LowTempAlarm.Name); + ini.SetValue("AlarmNames", "pressDown", PressChangeAlarm.NameDown); + ini.SetValue("AlarmNames", "pressUp", PressChangeAlarm.NameUp); + ini.SetValue("AlarmNames", "rainAbove", HighRainTodayAlarm.Name); + ini.SetValue("AlarmNames", "rainRateAbove", HighRainRateAlarm.Name); + ini.SetValue("AlarmNames", "sensorLost", SensorAlarm.Name); + ini.SetValue("AlarmNames", "tempDown", TempChangeAlarm.NameDown); + ini.SetValue("AlarmNames", "tempUp", TempChangeAlarm.NameUp); + ini.SetValue("AlarmNames", "windAbove", HighWindAlarm.Name); + ini.SetValue("AlarmNames", "dataStopped", DataStoppedAlarm.Name); + ini.SetValue("AlarmNames", "batteryLow", BatteryLowAlarm.Name); + ini.SetValue("AlarmNames", "dataSpike", SpikeAlarm.Name); + ini.SetValue("AlarmNames", "upgrade", UpgradeAlarm.Name); + ini.SetValue("AlarmNames", "httpStopped", ThirdPartyAlarm.Name); + ini.SetValue("AlarmNames", "mySqlStopped", MySqlUploadAlarm.Name); + ini.SetValue("AlarmNames", "isRaining", IsRainingAlarm.Name); + ini.SetValue("AlarmNames", "newRecord", NewRecordAlarm.Name); + ini.SetValue("AlarmNames", "ftpStopped", FtpAlarm.Name); + ini.Flush(); LogMessage("Completed writing strings.ini file"); @@ -7800,8 +7962,6 @@ public void WriteStringsFile() public Timer WundTimer = new Timer(); public Timer WebTimer = new Timer(); public Timer AwekasTimer = new Timer(); - public Timer MQTTTimer = new Timer(); - //public Timer AirLinkTimer = new Timer(); public int DAVIS = 0; public int OREGON = 1; @@ -7905,7 +8065,7 @@ public int GetTCPport() } */ - public string GetLogFileName(DateTime thedate) + public string GetLogFileName(DateTime thedate) { // First determine the date for the log file. // If we're using 9am roll-over, the date should be 9 hours (10 in summer) @@ -8014,7 +8174,7 @@ public async void DoLogFile(DateTime timestamp, bool live) sb.Append(station.RainRate.ToString(RainFormat) + ListSeparator); sb.Append(station.RainToday.ToString(RainFormat) + ListSeparator); sb.Append(station.Pressure.ToString(PressFormat) + ListSeparator); - sb.Append(station.Raincounter.ToString(RainFormat) + ListSeparator); + sb.Append(station.RainCounter.ToString(RainFormat) + ListSeparator); sb.Append(station.IndoorTemperature.ToString(TempFormat) + ListSeparator); sb.Append(station.IndoorHumidity + ListSeparator); sb.Append(station.WindLatest.ToString(WindFormat) + ListSeparator); @@ -8081,7 +8241,7 @@ public async void DoLogFile(DateTime timestamp, bool live) values.Append(station.RainRate.ToString(RainFormat, InvC) + ","); values.Append(station.RainToday.ToString(RainFormat, InvC) + ","); values.Append(station.Pressure.ToString(PressFormat, InvC) + ","); - values.Append(station.Raincounter.ToString(RainFormat, InvC) + ","); + values.Append(station.RainCounter.ToString(RainFormat, InvC) + ","); values.Append(station.IndoorTemperature.ToString(TempFormat, InvC) + ","); values.Append(station.IndoorHumidity + ","); values.Append(station.WindLatest.ToString(WindFormat, InvC) + ","); @@ -9137,7 +9297,7 @@ private bool IsDaylightSavings() public string Beaufort(double Bspeed) // Takes speed in current unit, returns Bft number as text { - return station.Beaufort(Bspeed).ToString(); + return ConvertUnits.Beaufort(Bspeed).ToString(); } public string BeaufortDesc(double Bspeed) @@ -9145,7 +9305,7 @@ public string BeaufortDesc(double Bspeed) // Takes speed in current units, returns Bft description // Convert to Force - var force = station.Beaufort(Bspeed); + var force = ConvertUnits.Beaufort(Bspeed); switch (force) { case 0: @@ -9215,11 +9375,8 @@ public void Stop() WundTimer.Stop(); WebTimer.Stop(); AwekasTimer.Stop(); - MQTTTimer.Stop(); - //AirLinkTimer.Stop(); CustomHttpSecondsTimer.Stop(); CustomMysqlSecondsTimer.Stop(); - MQTTTimer.Stop(); } catch { } @@ -9245,9 +9402,6 @@ public void Stop() LogMessage("Stopping station..."); try { - station.Stop(); - LogMessage("Station stopped"); - if (station.HaveReadData) { LogMessage("Writing today.ini file"); @@ -9259,6 +9413,9 @@ public void Stop() LogMessage("No data read this session, today.ini not written"); } station.SaveWindData(); + + station.Stop(); + LogMessage("Station stopped"); } catch { } } @@ -10827,7 +10984,6 @@ public async Task DoIntervalUpload() return; } - tasklist.Add(Task.Run(async () => { try @@ -11069,7 +11225,6 @@ public async Task DoIntervalUpload() LogDebugMessage($"PHP[Int]: Moon image has a semaphore [{uploadCountLimitSemaphoreSlim.CurrentCount}]"); #else await uploadCountLimitSemaphoreSlim.WaitAsync(cancellationToken); - #endif } catch (OperationCanceledException) @@ -11788,6 +11943,7 @@ public void LogFtpMessage(string message) { if (!string.IsNullOrEmpty(message)) LogMessage(message); + LogFluentFtpMessage(FtpTraceLevel.Info, message); } @@ -11832,6 +11988,7 @@ public void LogConsoleMessage(string message, ConsoleColor colour = ConsoleColor { message = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + message; } + Console.ForegroundColor = colour; Console.WriteLine(message); Console.ResetColor(); @@ -11872,6 +12029,11 @@ public string GetErrorLog() return arr.Reverse().ToJson(); } + public string ClearErrorLog() + { + ErrorList.Clear(); + return GetErrorLog(); + } private void CreateRealtimeFile(int cycle) { @@ -12263,27 +12425,8 @@ public void StartTimersAndSensors() WundTimer.Interval = Wund.Interval * 60 * 1000; // mins to millisecs } - AwekasTimer.Interval = AWEKAS.Interval * 1000; - MQTTTimer.Interval = MQTT.IntervalTime * 1000; // secs to millisecs - - - // 15/10/20 What is doing? Nothing - /* - if (AirLinkInEnabled || AirLinkOutEnabled) - { - AirLinkTimer.Interval = 60 * 1000; // 1 minute - AirLinkTimer.Enabled = true; - AirLinkTimer.Elapsed += AirLinkTimerTick; - } - */ - - if (MQTT.EnableInterval) - { - MQTTTimer.Enabled = true; - } - if (WundList == null) { // we've already been through here @@ -13845,6 +13988,7 @@ private void LogPrimaryAqSensor() } } + /* private void PingCompletedCallback(object sender, PingCompletedEventArgs e) { // If an error occurred, display the exception to the user. @@ -13859,6 +14003,7 @@ private void PingCompletedCallback(object sender, PingCompletedEventArgs e) //pingReply = e.Reply; } + */ private void CreateRequiredFolders() { @@ -14408,6 +14553,7 @@ public class MqttTemplateMember public string data { get; set; } public bool retain { get; set; } public string doNotTriggerOnTags { get; set; } + public int? interval { get; set; } } public class MySqlGeneralSettings diff --git a/CumulusMX/CumulusMX.csproj b/CumulusMX/CumulusMX.csproj index 1c35417c..788d10a7 100644 --- a/CumulusMX/CumulusMX.csproj +++ b/CumulusMX/CumulusMX.csproj @@ -48,19 +48,18 @@ - - - - - + + + + - - + + @@ -77,7 +76,7 @@ CumulusMX.Program AnyCPU Copyright © 2015-2023 Cumulus MX - 3.27.1.3263 + 3.28.0.3269 diff --git a/CumulusMX/CumulusService.cs b/CumulusMX/CumulusService.cs index 009ed727..f4db998c 100644 --- a/CumulusMX/CumulusService.cs +++ b/CumulusMX/CumulusService.cs @@ -52,7 +52,8 @@ protected override void OnStart(string[] args) { } } - Program.cumulus = new Cumulus(httpport, debug, startParams); + Program.cumulus = new Cumulus(); + Program.cumulus.Initialise(httpport, debug, startParams); } protected override void OnStop() diff --git a/CumulusMX/DataEditor.cs b/CumulusMX/DataEditor.cs index abb2e4d5..3de89854 100644 --- a/CumulusMX/DataEditor.cs +++ b/CumulusMX/DataEditor.cs @@ -48,10 +48,10 @@ internal string EditRainToday(IHttpContext context) try { var raintoday = double.Parse(raintodaystring, CultureInfo.InvariantCulture); - cumulus.LogMessage("Before rain today edit, raintoday=" + station.RainToday.ToString(cumulus.RainFormat) + " Raindaystart=" + station.raindaystart.ToString(cumulus.RainFormat)); + cumulus.LogMessage("Before rain today edit, raintoday=" + station.RainToday.ToString(cumulus.RainFormat) + " Raindaystart=" + station.RainCounterDayStart.ToString(cumulus.RainFormat)); station.RainToday = raintoday; - station.raindaystart = station.Raincounter - (station.RainToday / cumulus.Calib.Rain.Mult); - cumulus.LogMessage("After rain today edit, raintoday=" + station.RainToday.ToString(cumulus.RainFormat) + " Raindaystart=" + station.raindaystart.ToString(cumulus.RainFormat)); + station.RainCounterDayStart = station.RainCounter - (station.RainToday / cumulus.Calib.Rain.Mult); + cumulus.LogMessage("After rain today edit, raintoday=" + station.RainToday.ToString(cumulus.RainFormat) + " Raindaystart=" + station.RainCounterDayStart.ToString(cumulus.RainFormat)); // force the rainthismonth/rainthisyear values to be recalculated station.UpdateYearMonthRainfall(); } @@ -64,8 +64,8 @@ internal string EditRainToday(IHttpContext context) return new JsonObject { ["raintoday"] = station.RainToday.ToString(cumulus.RainFormat, invC), - ["raincounter"] = station.Raincounter.ToString(cumulus.RainFormat, invC), - ["startofdayrain"] = station.raindaystart.ToString(cumulus.RainFormat, invC), + ["raincounter"] = station.RainCounter.ToString(cumulus.RainFormat, invC), + ["startofdayrain"] = station.RainCounterDayStart.ToString(cumulus.RainFormat, invC), ["rainmult"] = cumulus.Calib.Rain.Mult.ToString("F3", invC) }.ToJson(); } @@ -78,8 +78,8 @@ internal string GetRainTodayEditData() return new JsonObject { ["raintoday"] = station.RainToday.ToString(cumulus.RainFormat, invC), - ["raincounter"] = station.Raincounter.ToString(cumulus.RainFormat, invC), - ["startofdayrain"] = station.raindaystart.ToString(cumulus.RainFormat, invC), + ["raincounter"] = station.RainCounter.ToString(cumulus.RainFormat, invC), + ["startofdayrain"] = station.RainCounterDayStart.ToString(cumulus.RainFormat, invC), ["rainmult"] = cumulus.Calib.Rain.Mult.ToString("F3", invC), ["step"] = step }.ToJson(); @@ -627,8 +627,8 @@ internal string GetRecordsDayFile(string recordType, DateTime? start = null, Dat ["lowBarometerTimeDayfile"] = lowBaro.GetTsString(timeStampFormat), ["highGustValDayfile"] = highGust.GetValString(cumulus.WindFormat), ["highGustTimeDayfile"] = highGust.GetTsString(timeStampFormat), - ["highWindValDayfile"] = highWindRun.GetValString(cumulus.WindRunFormat), - ["highWindTimeDayfile"] = highWindRun.GetTsString(timeStampFormat), + ["highWindValDayfile"] = highWind.GetValString(cumulus.WindRunFormat), + ["highWindTimeDayfile"] = highWind.GetTsString(timeStampFormat), ["highWindRunValDayfile"] = highWindRun.GetValString(cumulus.WindRunFormat), ["highWindRunTimeDayfile"] = highWindRun.GetTsString(dateStampFormat), ["highRainRateValDayfile"] = highRainRate.GetValString(cumulus.RainFormat), diff --git a/CumulusMX/DataStruct.cs b/CumulusMX/DataStruct.cs index 3fc32f38..afdf1f18 100644 --- a/CumulusMX/DataStruct.cs +++ b/CumulusMX/DataStruct.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Runtime.Serialization; namespace CumulusMX @@ -20,12 +21,9 @@ public DataStruct(Cumulus cumulus, double outdoorTemp, int outdoorHum, double av string highHeatIndexTodayTime, double highAppTempToday, double lowAppTempToday, string highAppTempTodayTime, string lowAppTempTodayTime, int currentSolarMax, double alltimeHighPressure, double alltimeLowPressure, double sunshineHours, string domWindDir, string lastRainTipISO, double highHourlyRainToday, string highHourlyRainTodayTime, string highBeaufortToday, string beaufort, string beaufortDesc, string lastDataRead, - bool dataStopped, double stormRain, string stormRainStart, int cloudbase, string cloudbaseUnit, double last24hourRain, bool alarmLowTemp, - bool alarmHighTemp, bool alarmTempUp, bool alarmTempDown, bool alarmRain, bool alarmRainRate, bool alarmLowPress, bool alarmHighPress, - bool alarmPressUp, bool alarmPressDown, bool alarmGust, bool alarmWind, bool alarmSensor, bool alarmBattery, bool alarmSpike, bool alarmUpgrade, - bool alarmHttp, bool alarmMySql, bool alarmRaining, + bool dataStopped, double stormRain, string stormRainStart, int cloudbase, string cloudbaseUnit, double last24hourRain, double feelsLike, double highFeelsLikeToday, string highFeelsLikeTodayTime, double lowFeelsLikeToday, string lowFeelsLikeTodayTime, - double highHumidexToday, string highHumidexTodayTime) + double highHumidexToday, string highHumidexTodayTime, List alarms) { this.cumulus = cumulus; OutdoorTemp = outdoorTemp; @@ -126,25 +124,7 @@ public DataStruct(Cumulus cumulus, double outdoorTemp, int outdoorHum, double av StormRainStart = stormRainStart; Cloudbase = cloudbase; CloudbaseUnit = cloudbaseUnit; - AlarmLowTemp = alarmLowTemp; - AlarmHighTemp = alarmHighTemp; - AlarmTempUp = alarmTempUp; - AlarmTempDn = alarmTempDown; - AlarmRain = alarmRain; - AlarmRainRate = alarmRainRate; - AlarmLowPress = alarmLowPress; - AlarmHighPress = alarmHighPress; - AlarmPressUp = alarmPressUp; - AlarmPressDn = alarmPressDown; - AlarmGust = alarmGust; - AlarmWind = alarmWind; - AlarmSensor = alarmSensor; - AlarmBattery = alarmBattery; - AlarmSpike = alarmSpike; - AlarmUpgrade = alarmUpgrade; - AlarmHttp = alarmHttp; - AlarmMySql = alarmMySql; - AlarmIsRaining = alarmRaining; + Alarms = alarms; } [IgnoreDataMember] @@ -777,60 +757,6 @@ public string Build public bool DataStopped { get; set; } [DataMember] - public bool AlarmLowTemp { get; set; } - - [DataMember] - public bool AlarmHighTemp { get; set; } - - [DataMember] - public bool AlarmTempUp { get; set; } - - [DataMember] - public bool AlarmTempDn { get; set; } - - [DataMember] - public bool AlarmRain { get; set; } - - [DataMember] - public bool AlarmRainRate { get; set; } - - [DataMember] - public bool AlarmLowPress { get; set; } - - [DataMember] - public bool AlarmHighPress { get; set; } - - [DataMember] - public bool AlarmPressUp { get; set; } - - [DataMember] - public bool AlarmPressDn { get; set; } - - [DataMember] - public bool AlarmGust { get; set; } - - [DataMember] - public bool AlarmWind { get; set; } - - [DataMember] - public bool AlarmSensor { get; set; } - - [DataMember] - public bool AlarmBattery { get; set; } - - [DataMember] - public bool AlarmSpike { get; set; } - - [DataMember] - public bool AlarmUpgrade { get; set; } - - [DataMember] - public bool AlarmHttp { get; set; } - - [DataMember] - public bool AlarmMySql { get; set; } - - [DataMember] - public bool AlarmIsRaining { get; set; } + public List Alarms { get; set; } } } diff --git a/CumulusMX/DavisAirLink.cs b/CumulusMX/DavisAirLink.cs index cb86e58f..84f8dbcc 100644 --- a/CumulusMX/DavisAirLink.cs +++ b/CumulusMX/DavisAirLink.cs @@ -411,11 +411,11 @@ private void DecodeAlCurrent(string currentJson) if (indoor) { - cumulus.airLinkDataIn.temperature = station.ConvertTempFToUser(rec.temp); + cumulus.airLinkDataIn.temperature = ConvertUnits.TempFToUser(rec.temp); } else { - cumulus.airLinkDataOut.temperature = station.ConvertTempFToUser(rec.temp); + cumulus.airLinkDataOut.temperature = ConvertUnits.TempFToUser(rec.temp); } } catch (Exception ex) @@ -611,7 +611,6 @@ private void GetWlHistoricData() apiKey = cumulus.WllApiKey; apiSecret = cumulus.WllApiSecret; stationId = cumulus.WllStationId; - } if (stationId < 10) @@ -660,7 +659,7 @@ private void GetWlHistoricData() int responseCode; var request = new HttpRequestMessage(HttpMethod.Get, historicUrl.ToString()); - request.Headers.Add("X-Api-Secret", cumulus.WllApiSecret); + request.Headers.Add("X-Api-Secret", apiSecret); // we want to do this synchronously, so .Result using (var response = Cumulus.MyHttpClient.SendAsync(request).Result) @@ -878,11 +877,11 @@ public void DecodeAlHistoric(int dataType, string json) { if (indoor) { - cumulus.airLinkDataIn.temperature = station.ConvertTempFToUser(data17.temp_avg); + cumulus.airLinkDataIn.temperature = ConvertUnits.TempFToUser(data17.temp_avg); } else { - cumulus.airLinkDataOut.temperature = station.ConvertTempFToUser(data17.temp_avg); + cumulus.airLinkDataOut.temperature = ConvertUnits.TempFToUser(data17.temp_avg); } } } @@ -1010,6 +1009,10 @@ private void GetWlHistoricHealth() { WlHistory histObj; + // Are we using the same WL APIv2 as a WLL device? + if (cumulus.StationType == 11 && !standalone) + return; + string apiKey; string apiSecret; int stationId; @@ -1297,15 +1300,9 @@ private bool GetAvailableStationIds() var unixDateTime = Utils.ToUnixTime(DateTime.Now); // Are we using the same WL APIv2 as a WLL device? - if (cumulus.StationType == 11 && cumulus.WllApiKey == cumulus.AirLinkApiKey) + if (cumulus.StationType == 11 && !standalone) return true; - SortedDictionary parameters = new SortedDictionary - { - { "api-key", cumulus.AirLinkApiKey }, - { "t", unixDateTime.ToString() } - }; - var stationsUrl = "https://api.weatherlink.com/v2/stations?api-key=" + cumulus.AirLinkApiKey; cumulus.LogDebugMessage($"WeatherLink Stations URL = {stationsUrl.ToString().Replace(cumulus.AirLinkApiKey, "API_KEY")}"); @@ -1380,6 +1377,10 @@ private void GetAvailableSensors() { WlSensorList sensorsObj; + // Are we using the same WL APIv2 as a WLL device? + if (cumulus.StationType == 11 && !standalone) + return; + var unixDateTime = Utils.ToUnixTime(DateTime.Now); if (string.IsNullOrEmpty(cumulus.AirLinkApiKey) || string.IsNullOrEmpty(cumulus.AirLinkApiSecret)) @@ -1388,12 +1389,6 @@ private void GetAvailableSensors() return; } - if ((indoor && cumulus.AirLinkInStationId < 10) || (!indoor && cumulus.AirLinkOutStationId < 10)) - { - cumulus.LogWarningMessage($"GetAvailableSensors: No WeatherLink AirLink API station ID has been configured, aborting!"); - return; - } - var sensorsUrl = "https://api.weatherlink.com/v2/sensors?api-key=" + cumulus.AirLinkApiKey; cumulus.LogDebugMessage($"GetAvailableSensors: URL = {sensorsUrl.ToString().Replace(cumulus.AirLinkApiKey, "API_KEY")}"); diff --git a/CumulusMX/DavisCloudStation.cs b/CumulusMX/DavisCloudStation.cs index a139f972..94968f2c 100644 --- a/CumulusMX/DavisCloudStation.cs +++ b/CumulusMX/DavisCloudStation.cs @@ -580,15 +580,15 @@ private void DecodeCurrent(List sensors) DoOutdoorHumidity(Convert.ToInt32(data.hum_out.Value), timestamp); if (data.temp_out.HasValue) - DoOutdoorTemp(ConvertTempFToUser(data.temp_out.Value), timestamp); + DoOutdoorTemp(ConvertUnits.TempFToUser(data.temp_out.Value), timestamp); if (data.dew_point.HasValue) - DoOutdoorDewpoint(ConvertTempFToUser(data.dew_point.Value), timestamp); + DoOutdoorDewpoint(ConvertUnits.TempFToUser(data.dew_point.Value), timestamp); if (data.wind_chill.HasValue) { // use wind chill from WLL - DoWindChill(ConvertTempFToUser(data.wind_chill.Value), timestamp); + DoWindChill(ConvertUnits.TempFToUser(data.wind_chill.Value), timestamp); } //TODO: Wet Bulb? rec["wet_bulb"] - No, we already have humidity //TODO: Heat Index? rec["heat_index"] - No, Cumulus always calculates HI @@ -603,19 +603,19 @@ private void DecodeCurrent(List sensors) try { if (data.temp_extra_1.HasValue) - DoExtraTemp(ConvertTempFToUser(data.temp_extra_1.Value), 1); + DoExtraTemp(ConvertUnits.TempFToUser(data.temp_extra_1.Value), 1); if (data.temp_extra_2.HasValue) - DoExtraTemp(ConvertTempFToUser(data.temp_extra_2.Value), 2); + DoExtraTemp(ConvertUnits.TempFToUser(data.temp_extra_2.Value), 2); if (data.temp_extra_3.HasValue) - DoExtraTemp(ConvertTempFToUser(data.temp_extra_3.Value), 3); + DoExtraTemp(ConvertUnits.TempFToUser(data.temp_extra_3.Value), 3); if (data.temp_extra_4.HasValue) - DoExtraTemp(ConvertTempFToUser(data.temp_extra_4.Value), 4); + DoExtraTemp(ConvertUnits.TempFToUser(data.temp_extra_4.Value), 4); if (data.temp_extra_5.HasValue) - DoExtraTemp(ConvertTempFToUser(data.temp_extra_5.Value), 5); + DoExtraTemp(ConvertUnits.TempFToUser(data.temp_extra_5.Value), 5); if (data.temp_extra_6.HasValue) - DoExtraTemp(ConvertTempFToUser(data.temp_extra_6.Value), 6); + DoExtraTemp(ConvertUnits.TempFToUser(data.temp_extra_6.Value), 6); if (data.temp_extra_7.HasValue) - DoExtraTemp(ConvertTempFToUser(data.temp_extra_7.Value), 7); + DoExtraTemp(ConvertUnits.TempFToUser(data.temp_extra_7.Value), 7); if (data.hum_extra_1.HasValue) DoExtraHum(data.hum_extra_1.Value, 1); @@ -645,9 +645,9 @@ private void DecodeCurrent(List sensors) if (timestamp == DateTime.MinValue) timestamp = Utils.FromUnixTime(data.ts); - var gust = ConvertWindMPHToUser(data.wind_gust_10_min ?? 0); - var avg = ConvertWindMPHToUser(data.wind_speed_10_min_avg ?? 0); - double wind = ConvertWindMPHToUser(data.wind_speed ?? 0); + var gust = ConvertUnits.WindMPHToUser(data.wind_gust_10_min ?? 0); + var avg = ConvertUnits.WindMPHToUser(data.wind_speed_10_min_avg ?? 0); + double wind = ConvertUnits.WindMPHToUser(data.wind_speed ?? 0); int wdir = data.wind_dir ?? 0; DoWind(gust, wdir, avg, timestamp); @@ -795,20 +795,20 @@ private void DecodeCurrent(List sensors) DoOutdoorHumidity(Convert.ToInt32(data.hum.Value), timestamp); if (data.temp.HasValue) - DoOutdoorTemp(ConvertTempFToUser(data.temp.Value), timestamp); + DoOutdoorTemp(ConvertUnits.TempFToUser(data.temp.Value), timestamp); if (data.dew_point.HasValue) - DoOutdoorDewpoint(ConvertTempFToUser(data.dew_point.Value), timestamp); + DoOutdoorDewpoint(ConvertUnits.TempFToUser(data.dew_point.Value), timestamp); if (data.wind_chill.HasValue) { // use wind chill from WLL - DoWindChill(ConvertTempFToUser(data.wind_chill.Value), timestamp); + DoWindChill(ConvertUnits.TempFToUser(data.wind_chill.Value), timestamp); } if (data.thsw_index.HasValue) { - THSWIndex = ConvertTempFToUser(data.thsw_index.Value); + THSWIndex = ConvertUnits.TempFToUser(data.thsw_index.Value); } //TODO: Wet Bulb? rec["wet_bulb"] - No, we already have humidity @@ -838,7 +838,7 @@ private void DecodeCurrent(List sensors) { cumulus.LogDebugMessage($"WL current: using extra temp data from TxId {data.tx_id}"); - DoExtraTemp(ConvertTempFToUser(data.temp.Value), tempTxId); + DoExtraTemp(ConvertUnits.TempFToUser(data.temp.Value), tempTxId); } if (cumulus.WllExtraHumTx[tempTxId] && data.hum.HasValue) @@ -878,13 +878,13 @@ private void DecodeCurrent(List sensors) if (timestamp == DateTime.MinValue) timestamp = Utils.FromUnixTime(data.ts); - var gust = ConvertWindMPHToUser(data.wind_speed_hi_last_10_min ?? 0); - var avg = ConvertWindMPHToUser(data.wind_speed_avg_last_10_min ?? 0); - var last = ConvertWindMPHToUser(data.wind_speed_last ?? 0); + var gust = ConvertUnits.WindMPHToUser(data.wind_speed_hi_last_10_min ?? 0); + var avg = ConvertUnits.WindMPHToUser(data.wind_speed_avg_last_10_min ?? 0); + var last = ConvertUnits.WindMPHToUser(data.wind_speed_last ?? 0); // pesky null values from WLL when it is calm int wdir = data.wind_dir_scalar_avg_last_1_min ?? 0; - double wind = ConvertWindMPHToUser(data.wind_speed_last ?? 0); + double wind = ConvertUnits.WindMPHToUser(data.wind_speed_last ?? 0); DoWind(last, wdir, avg, timestamp); @@ -894,7 +894,7 @@ private void DecodeCurrent(List sensors) //if (cumulus.StationOptions.PeakGustMinutes >= 2) //{ - // var gust = ConvertWindMPHToUser(data.wind_speed_hi_last_2_min ?? 0); + // var gust = ConvertUnits.WindMPHToUser(data.wind_speed_hi_last_2_min ?? 0); // var gustCal = cumulus.Calib.WindGust.Calibrate(gust); // var gustDir = data.wind_dir_at_hi_speed_last_2_min ?? 0; // var gustDirCal = gustDir == 0 ? 0 : (int) cumulus.Calib.WindDir.Calibrate(gustDir); @@ -1088,15 +1088,15 @@ private void DecodeCurrent(List sensors) if (data3.bar_sea_level.HasValue) { - DoPressure(ConvertPressINHGToUser(data3.bar_sea_level.Value), Utils.FromUnixTime(data3.ts)); + DoPressure(ConvertUnits.PressINHGToUser(data3.bar_sea_level.Value), Utils.FromUnixTime(data3.ts)); } // Altimeter from absolute if (data3.bar_absolute.HasValue) { - StationPressure = ConvertPressINHGToUser(data3.bar_absolute.Value); + StationPressure = ConvertUnits.PressINHGToUser(data3.bar_absolute.Value); // Or do we use calibration? The VP2 code doesn't? - //StationPressure = ConvertPressINHGToUser(rec.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; - AltimeterPressure = ConvertPressMBToUser(StationToAltimeter(ConvertUserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); + //StationPressure = ConvertUnits.PressINHGToUser(rec.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; + AltimeterPressure = ConvertUnits.PressMBToUser(StationToAltimeter(ConvertUnits.UserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); } } catch (Exception ex) @@ -1117,7 +1117,7 @@ private void DecodeCurrent(List sensors) try { if (data4.temp_in.HasValue) - DoIndoorTemp(ConvertTempFToUser(data4.temp_in.Value)); + DoIndoorTemp(Convert.TempFToUser(data4.temp_in.Value)); } catch (Exception ex) { @@ -1271,7 +1271,7 @@ private void DecodeCurrent(List sensors) { var val = (double?) data[idx]; if (val.HasValue) - DoSoilTemp(ConvertTempFToUser(val.Value), 1); + DoSoilTemp(ConvertUnits.TempFToUser(val.Value), 1); } catch (Exception ex) { @@ -1286,7 +1286,7 @@ private void DecodeCurrent(List sensors) { var val = (double?) data[idx]; if (val.HasValue) - DoSoilTemp(ConvertTempFToUser(val.Value), 2); + DoSoilTemp(ConvertUnits.TempFToUser(val.Value), 2); } catch (Exception ex) { @@ -1301,7 +1301,7 @@ private void DecodeCurrent(List sensors) { var val = (double?) data[idx]; if (val.HasValue) - DoSoilTemp(ConvertTempFToUser(val.Value), 3); + DoSoilTemp(ConvertUnits.TempFToUser(val.Value), 3); } catch (Exception ex) { @@ -1316,7 +1316,7 @@ private void DecodeCurrent(List sensors) { var val = (double?) data[idx]; if (val.HasValue) - DoSoilTemp(ConvertTempFToUser(val.Value), 4); + DoSoilTemp(ConvertUnits.TempFToUser(val.Value), 4); } catch (Exception ex) { @@ -1364,7 +1364,7 @@ private void DecodeCurrent(List sensors) // Now we have the primary data, calculate the derived data if (cumulus.StationOptions.CalculatedWC) { - if (ConvertUserWindToMS(WindAverage) < 1.5) + if (ConvertUnits.UserWindToMS(WindAverage) < 1.5) { // wind speed too low, use the temperature DoWindChill(OutdoorTemperature, timestamp); @@ -1372,7 +1372,7 @@ private void DecodeCurrent(List sensors) else { // calculate wind chill from calibrated C temp and calibrated wind in KPH - DoWindChill(ConvertTempCToUser(MeteoLib.WindChill(ConvertUserTempToC(OutdoorTemperature), ConvertUserWindToKPH(WindAverage))), timestamp); + DoWindChill(ConvertUnits.TempCToUser(MeteoLib.WindChill(ConvertUnits.UserTempToC(OutdoorTemperature), ConvertUnits.UserWindToKPH(WindAverage))), timestamp); } } @@ -1420,13 +1420,13 @@ private double ConvertRainClicksToUser(double clicks, int size) switch (size) { case 1: - return ConvertRainINToUser(clicks * 0.01); + return ConvertUnits.RainINToUser(clicks * 0.01); case 2: - return ConvertRainMMToUser(clicks * 0.2); + return ConvertUnits.RainMMToUser(clicks * 0.2); case 3: - return ConvertRainMMToUser(clicks * 0.1); + return ConvertUnits.RainMMToUser(clicks * 0.1); case 4: - return ConvertRainINToUser(clicks * 0.001); + return ConvertUnits.RainINToUser(clicks * 0.001); default: switch (cumulus.DavisOptions.RainGaugeType) { @@ -1440,9 +1440,9 @@ private double ConvertRainClicksToUser(double clicks, int size) return clicks * 0.01; // Rain gauge is metric, convert to user unit case 0: - return ConvertRainMMToUser(clicks * 0.2); + return ConvertUnits.RainMMToUser(clicks * 0.2); default: - return ConvertRainINToUser(clicks * 0.01); + return ConvertUnits.RainINToUser(clicks * 0.01); } } } @@ -1851,13 +1851,13 @@ private void GetWlHistoricData(BackgroundWorker worker) } AddRecentDataWithAq(timestamp, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, - OutdoorHumidity, Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); + OutdoorHumidity, Pressure, RainToday, SolarRad, UV, RainCounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); DoTrendValues(timestamp); if (cumulus.StationOptions.CalculatedET && timestamp.Minute == 0) { // Start of a new hour, and we want to calculate ET in Cumulus - CalculateEvaoptranspiration(timestamp); + CalculateEvapotranspiration(timestamp); } UpdateStatusPanel(timestamp); @@ -1943,7 +1943,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // do high temp if (data.temp_out_hi.HasValue) { - DoOutdoorTemp(ConvertTempFToUser(data.temp_out_hi.Value), lastRecordTime); + DoOutdoorTemp(ConvertUnits.TempFToUser(data.temp_out_hi.Value), lastRecordTime); } else { @@ -1953,7 +1953,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // do low temp if (data.temp_out_lo.HasValue) { - DoOutdoorTemp(ConvertTempFToUser(data.temp_out_lo.Value), lastRecordTime); + DoOutdoorTemp(ConvertUnits.TempFToUser(data.temp_out_lo.Value), lastRecordTime); } else { @@ -1963,13 +1963,13 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // do last temp if (data.temp_out.HasValue) { - DoOutdoorTemp(ConvertTempFToUser(data.temp_out.Value), lastRecordTime); + DoOutdoorTemp(ConvertUnits.TempFToUser(data.temp_out.Value), lastRecordTime); if (!current) { // set the values for daily average, arch_int is in seconds, but always whole minutes tempsamplestoday += data.arch_int / 60; - TempTotalToday += ConvertTempFToUser(data.temp_out.Value) * data.arch_int / 60; + TempTotalToday += ConvertUnits.TempFToUser(data.temp_out.Value) * data.arch_int / 60; // update chill hours if (OutdoorTemperature < cumulus.ChillHourThreshold) @@ -2002,7 +2002,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // do last DP if (data.dew_point_out.HasValue) { - DoOutdoorDewpoint(ConvertTempFToUser(data.dew_point_out.Value), lastRecordTime); + DoOutdoorDewpoint(ConvertUnits.TempFToUser(data.dew_point_out.Value), lastRecordTime); } else { @@ -2022,7 +2022,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // do last WC if (data.wind_chill.HasValue) { - DoWindChill(ConvertTempFToUser(data.wind_chill.Value), lastRecordTime); + DoWindChill(ConvertUnits.TempFToUser(data.wind_chill.Value), lastRecordTime); } else { @@ -2052,8 +2052,8 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr { if (data.wind_speed_hi.HasValue && data.wind_dir_of_hi.HasValue && data.wind_speed_avg.HasValue) { - var gust = ConvertWindMPHToUser(data.wind_speed_hi.Value); - var spd = ConvertWindMPHToUser(data.wind_speed_avg.Value); + var gust = ConvertUnits.WindMPHToUser(data.wind_speed_hi.Value); + var spd = ConvertUnits.WindMPHToUser(data.wind_speed_avg.Value); // dir is a direction code: 0=N, 1=NNE, ... 14=NW, 15=NNW - convert to degress var dir = (int) ((data.wind_dir_of_hi ?? 0) * 22.5); cumulus.LogDebugMessage($"WL.com historic: using wind data from TxId {data.tx_id}"); @@ -2068,7 +2068,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data.wind_speed_avg.HasValue) { - WindAverage = cumulus.Calib.WindSpeed.Calibrate(ConvertWindMPHToUser(data.wind_speed_avg.Value)); + WindAverage = cumulus.Calib.WindSpeed.Calibrate(ConvertUnits.WindMPHToUser(data.wind_speed_avg.Value)); if (!current) { @@ -2121,7 +2121,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr { cumulus.LogDebugMessage($"WL.com historic: Adding rain {rain.ToString(cumulus.RainFormat)}"); } - rain += Raincounter; + rain += RainCounter; if (rainrate < 0) { @@ -2154,7 +2154,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data.bar != null) { // leave it at current value - DoPressure(ConvertPressINHGToUser((double) data.bar), lastRecordTime); + DoPressure(ConvertUnits.PressINHGToUser((double) data.bar), lastRecordTime); } else { @@ -2164,10 +2164,10 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // Altimeter from absolute if (data.abs_press != null) { - StationPressure = ConvertPressINHGToUser((double) data.abs_press); + StationPressure = ConvertUnits.PressINHGToUser((double) data.abs_press); // Or do we use calibration? The VP2 code doesn't? - //StationPressure = ConvertPressINHGToUser(data.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; - AltimeterPressure = ConvertPressMBToUser(StationToAltimeter(ConvertUserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); + //StationPressure = ConvertUnits.PressINHGToUser(data.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; + AltimeterPressure = ConvertUnits.PressMBToUser(StationToAltimeter(ConvertUnits.UserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); } } catch (Exception ex) @@ -2236,8 +2236,8 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // The number is the total for the one hour period. // This is unlike the existing VP2 when the ET is an annual running total // So we try and mimic the VP behaviour - var newET = AnnualETTotal + ConvertRainINToUser(data.et.Value); - cumulus.LogDebugMessage($"WLL DecodeHistoric: Adding {ConvertRainINToUser(data.et.Value):F3} to ET"); + var newET = AnnualETTotal + ConvertUnits.RainINToUser(data.et.Value); + cumulus.LogDebugMessage($"WLL DecodeHistoric: Adding {ConvertUnits.RainINToUser(data.et.Value):F3} to ET"); DoET(newET, lastRecordTime); } } @@ -2438,7 +2438,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data.temp_hi_at != 0 && data.temp_hi != null) { ts = Utils.FromUnixTime(data.temp_hi_at); - DoOutdoorTemp(ConvertTempFToUser((double) data.temp_hi), ts); + DoOutdoorTemp(ConvertUnits.TempFToUser((double) data.temp_hi), ts); } else { @@ -2449,7 +2449,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data.temp_lo_at != 0 && data.temp_lo != null) { ts = Utils.FromUnixTime(data.temp_lo_at); - DoOutdoorTemp(ConvertTempFToUser((double) data.temp_lo), ts); + DoOutdoorTemp(ConvertUnits.TempFToUser((double) data.temp_lo), ts); } else { @@ -2459,13 +2459,13 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // do last temp if (data.temp_last != null) { - DoOutdoorTemp(ConvertTempFToUser((double) data.temp_last), lastRecordTime); + DoOutdoorTemp(ConvertUnits.TempFToUser((double) data.temp_last), lastRecordTime); if (!current) { // set the values for daily average, arch_int is in seconds, but always whole minutes tempsamplestoday += data.arch_int / 60; - TempTotalToday += ConvertTempFToUser(data.temp_avg) * data.arch_int / 60; + TempTotalToday += ConvertUnits.TempFToUser(data.temp_avg) * data.arch_int / 60; // update chill hours if (OutdoorTemperature < cumulus.ChillHourThreshold) @@ -2496,7 +2496,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data.dew_point_hi_at != 0 && data.dew_point_hi != null) { ts = Utils.FromUnixTime(data.dew_point_hi_at); - DoOutdoorDewpoint(ConvertTempFToUser((double) data.dew_point_hi), ts); + DoOutdoorDewpoint(ConvertUnits.TempFToUser((double) data.dew_point_hi), ts); } else { @@ -2507,7 +2507,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data.dew_point_lo_at != 0 && data.dew_point_lo != null) { ts = Utils.FromUnixTime(data.dew_point_lo_at); - DoOutdoorDewpoint(ConvertTempFToUser((double) data.dew_point_lo), ts); + DoOutdoorDewpoint(ConvertUnits.TempFToUser((double) data.dew_point_lo), ts); } else { @@ -2517,7 +2517,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // do last DP if (data.dew_point_last != null) { - DoOutdoorDewpoint(ConvertTempFToUser((double) data.dew_point_last), lastRecordTime); + DoOutdoorDewpoint(ConvertUnits.TempFToUser((double) data.dew_point_last), lastRecordTime); } else { @@ -2538,7 +2538,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data.wind_chill_lo_at != 0 && data.wind_chill_lo != null) { ts = Utils.FromUnixTime(data.wind_chill_lo_at); - DoWindChill(ConvertTempFToUser((double) data.wind_chill_lo), ts); + DoWindChill(ConvertUnits.TempFToUser((double) data.wind_chill_lo), ts); } else { @@ -2548,7 +2548,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // do last WC if (data.wind_chill_last != null) { - DoWindChill(ConvertTempFToUser((double) data.wind_chill_last), lastRecordTime); + DoWindChill(ConvertUnits.TempFToUser((double) data.wind_chill_last), lastRecordTime); } else { @@ -2577,7 +2577,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr { cumulus.LogDebugMessage($"WL.com historic: using extra temp data from TxId {data.tx_id}"); - DoExtraTemp(ConvertTempFToUser((double) data.temp_last), tempTxId); + DoExtraTemp(ConvertUnits.TempFToUser((double) data.temp_last), tempTxId); } } catch (Exception ex) @@ -2619,8 +2619,8 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr { if (data.wind_speed_hi != null && data.wind_speed_hi_dir != null && data.wind_speed_avg != null) { - var gust = ConvertWindMPHToUser((double) data.wind_speed_hi); - var spd = ConvertWindMPHToUser((double) data.wind_speed_avg); + var gust = ConvertUnits.WindMPHToUser((double) data.wind_speed_hi); + var spd = ConvertUnits.WindMPHToUser((double) data.wind_speed_avg); var dir = data.wind_speed_hi_dir ?? 0; cumulus.LogDebugMessage($"WL.com historic: using wind data from TxId {data.tx_id}"); DoWind(gust, dir, spd, lastRecordTime); @@ -2633,7 +2633,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data.wind_speed_avg != null) { - WindAverage = cumulus.Calib.WindSpeed.Calibrate(ConvertWindMPHToUser((double) data.wind_speed_avg)); + WindAverage = cumulus.Calib.WindSpeed.Calibrate(ConvertUnits.WindMPHToUser((double) data.wind_speed_avg)); if (!current) { @@ -2691,7 +2691,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr { cumulus.LogDebugMessage($"WL.com historic: Adding rain {rain.ToString(cumulus.RainFormat)}"); } - rain += Raincounter; + rain += RainCounter; if (rainrate < 0) { @@ -2783,8 +2783,8 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // The number is the total for the one hour period. // This is unlike the existing VP2 when the ET is an annual running total // So we try and mimic the VP behaviour - var newET = AnnualETTotal + ConvertRainINToUser((double) data.et); - cumulus.LogDebugMessage($"WLL DecodeHistoric: Adding {ConvertRainINToUser((double) data.et):F3} to ET"); + var newET = AnnualETTotal + ConvertUnits.RainINToUser((double) data.et); + cumulus.LogDebugMessage($"WLL DecodeHistoric: Adding {ConvertUnits.RainINToUser((double) data.et):F3} to ET"); DoET(newET, lastRecordTime); } } @@ -2970,7 +2970,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr } else { - DoSoilTemp(ConvertTempFToUser((double) data[idx]), 1); + DoSoilTemp(ConvertUnits.TempFToUser((double) data[idx]), 1); } } if (cumulus.WllExtraSoilTempTx2 == data.tx_id) @@ -2982,7 +2982,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr } else { - DoSoilTemp(ConvertTempFToUser((double) data[idx]), 2); + DoSoilTemp(ConvertUnits.TempFToUser((double) data[idx]), 2); } } if (cumulus.WllExtraSoilTempTx3 == data.tx_id) @@ -2994,7 +2994,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr } else { - DoSoilTemp(ConvertTempFToUser((double) data[idx]), 3); + DoSoilTemp(ConvertUnits.TempFToUser((double) data[idx]), 3); } } if (cumulus.WllExtraSoilTempTx4 == data.tx_id) @@ -3006,7 +3006,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr } else { - DoSoilTemp(ConvertTempFToUser((double) data[idx]), 4); + DoSoilTemp(ConvertUnits.TempFToUser((double) data[idx]), 4); } } } @@ -3038,7 +3038,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data13baro.bar_hi_at != 0 && data13baro.bar_hi != null) { ts = Utils.FromUnixTime(data13baro.bar_hi_at); - DoPressure(ConvertPressINHGToUser((double) data13baro.bar_hi), ts); + DoPressure(ConvertUnits.PressINHGToUser((double) data13baro.bar_hi), ts); } else { @@ -3048,7 +3048,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr if (data13baro.bar_lo_at != 0 && data13baro.bar_lo != null) { ts = Utils.FromUnixTime(data13baro.bar_lo_at); - DoPressure(ConvertPressINHGToUser((double) data13baro.bar_lo), ts); + DoPressure(ConvertUnits.PressINHGToUser((double) data13baro.bar_lo), ts); } else { @@ -3059,7 +3059,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr { // leave it at current value ts = Utils.FromUnixTime(data13baro.ts); - DoPressure(ConvertPressINHGToUser((double) data13baro.bar_sea_level), ts); + DoPressure(ConvertUnits.PressINHGToUser((double) data13baro.bar_sea_level), ts); } else { @@ -3069,10 +3069,10 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr // Altimeter from absolute if (data13baro.bar_absolute != null) { - StationPressure = ConvertPressINHGToUser((double) data13baro.bar_absolute); + StationPressure = ConvertUnits.PressINHGToUser((double) data13baro.bar_absolute); // Or do we use calibration? The VP2 code doesn't? - //StationPressure = ConvertPressINHGToUser(data.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; - AltimeterPressure = ConvertPressMBToUser(StationToAltimeter(ConvertUserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); + //StationPressure = ConvertUnits.PressINHGToUser(data.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; + AltimeterPressure = ConvertUnits.PressMBToUser(StationToAltimeter(ConvertUnits.UserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); } } catch (Exception ex) @@ -3104,7 +3104,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json, bool curr { if (data13temp.temp_in_last != null) { - DoIndoorTemp(ConvertTempFToUser((double) data13temp.temp_in_last)); + DoIndoorTemp(ConvertUnits.TempFToUser((double) data13temp.temp_in_last)); } else { @@ -3329,8 +3329,8 @@ private void DecodeISSHealth(WlHistorySensor sensor) // The number is the total for the one hour period. // This is unlike the existing VP2 when the ET is an annual running total // So we try and mimic the VP behaviour - var newET = AnnualETTotal + ConvertRainINToUser((double) data.et); - cumulus.LogDebugMessage($"XMTR Health: Adding {ConvertRainINToUser((double) data.et):F3} to ET"); + var newET = AnnualETTotal + ConvertUnits.RainINToUser((double) data.et); + cumulus.LogDebugMessage($"XMTR Health: Adding {ConvertUnits.RainINToUser((double) data.et):F3} to ET"); DoET(newET, DateTime.Now); } } diff --git a/CumulusMX/DavisStation.cs b/CumulusMX/DavisStation.cs index 7eefa3cb..579ffcf6 100644 --- a/CumulusMX/DavisStation.cs +++ b/CumulusMX/DavisStation.cs @@ -1549,12 +1549,12 @@ private void GetAndProcessLoopData(int number) if ((loopData.InsideTemperature > -200) && (loopData.InsideTemperature < 300)) { - DoIndoorTemp(ConvertTempFToUser(loopData.InsideTemperature)); + DoIndoorTemp(ConvertUnits.TempFToUser(loopData.InsideTemperature)); } if ((loopData.OutsideTemperature > -200) && (loopData.OutsideTemperature < 300)) { - DoOutdoorTemp(ConvertTempFToUser(loopData.OutsideTemperature), now); + DoOutdoorTemp(ConvertUnits.TempFToUser(loopData.OutsideTemperature), now); } else { @@ -1563,15 +1563,15 @@ private void GetAndProcessLoopData(int number) if ((loopData.Pressure >= 20) && (loopData.Pressure < 32.5)) { - DoPressure(ConvertPressINHGToUser(loopData.Pressure), now); + DoPressure(ConvertUnits.PressINHGToUser(loopData.Pressure), now); } else { cumulus.LogDebugMessage($"LOOP: Ignoring pressure data. Pressure={loopData.Pressure} inHg."); } - double wind = ConvertWindMPHToUser(loopData.CurrentWindSpeed); - double avgwind = ConvertWindMPHToUser(loopData.AvgWindSpeed); + double wind = ConvertUnits.WindMPHToUser(loopData.CurrentWindSpeed); + double avgwind = ConvertUnits.WindMPHToUser(loopData.AvgWindSpeed); // Check for sensible figures (spec says max for large cups is 175 mph, but up to 200 mph) // Average = 255 means the console hasn't calculated it yet @@ -1628,7 +1628,7 @@ private void GetAndProcessLoopData(int number) if ((loopData.AnnualET >= 0) && (loopData.AnnualET < 32000)) { - DoET(ConvertRainINToUser(loopData.AnnualET), now); + DoET(ConvertUnits.RainINToUser(loopData.AnnualET), now); } DoWindChill(OutdoorTemperature, now); @@ -1673,37 +1673,37 @@ private void GetAndProcessLoopData(int number) { if (loopData.ExtraTemp1 < 255) { - DoExtraTemp(ConvertTempFToUser(loopData.ExtraTemp1 - 90), 1); + DoExtraTemp(ConvertUnits.TempFToUser(loopData.ExtraTemp1 - 90), 1); } if (loopData.ExtraTemp2 < 255) { - DoExtraTemp(ConvertTempFToUser(loopData.ExtraTemp2 - 90), 2); + DoExtraTemp(ConvertUnits.TempFToUser(loopData.ExtraTemp2 - 90), 2); } if (loopData.ExtraTemp3 < 255) { - DoExtraTemp(ConvertTempFToUser(loopData.ExtraTemp3 - 90), 3); + DoExtraTemp(ConvertUnits.TempFToUser(loopData.ExtraTemp3 - 90), 3); } if (loopData.ExtraTemp4 < 255) { - DoExtraTemp(ConvertTempFToUser(loopData.ExtraTemp4 - 90), 4); + DoExtraTemp(ConvertUnits.TempFToUser(loopData.ExtraTemp4 - 90), 4); } if (loopData.ExtraTemp5 < 255) { - DoExtraTemp(ConvertTempFToUser(loopData.ExtraTemp5 - 90), 5); + DoExtraTemp(ConvertUnits.TempFToUser(loopData.ExtraTemp5 - 90), 5); } if (loopData.ExtraTemp6 < 255) { - DoExtraTemp(ConvertTempFToUser(loopData.ExtraTemp6 - 90), 6); + DoExtraTemp(ConvertUnits.TempFToUser(loopData.ExtraTemp6 - 90), 6); } if (loopData.ExtraTemp7 < 255) { - DoExtraTemp(ConvertTempFToUser(loopData.ExtraTemp7 - 90), 7); + DoExtraTemp(ConvertUnits.TempFToUser(loopData.ExtraTemp7 - 90), 7); } if (loopData.ExtraHum1 >= 0 && loopData.ExtraHum1 <= 100) @@ -1711,7 +1711,7 @@ private void GetAndProcessLoopData(int number) DoExtraHum(loopData.ExtraHum1, 1); if (loopData.ExtraTemp1 < 255) { - ExtraDewPoint[1] = ConvertTempCToUser(MeteoLib.DewPoint(ConvertUserTempToC(ExtraTemp[1]), ExtraHum[1])); + ExtraDewPoint[1] = ConvertUnits.TempCToUser(MeteoLib.DewPoint(ConvertUnits.UserTempToC(ExtraTemp[1]), ExtraHum[1])); } } @@ -1720,7 +1720,7 @@ private void GetAndProcessLoopData(int number) DoExtraHum(loopData.ExtraHum2, 2); if (loopData.ExtraTemp2 < 255) { - ExtraDewPoint[2] = ConvertTempCToUser(MeteoLib.DewPoint(ConvertUserTempToC(ExtraTemp[2]), ExtraHum[2])); + ExtraDewPoint[2] = ConvertUnits.TempCToUser(MeteoLib.DewPoint(ConvertUnits.UserTempToC(ExtraTemp[2]), ExtraHum[2])); } } @@ -1729,7 +1729,7 @@ private void GetAndProcessLoopData(int number) DoExtraHum(loopData.ExtraHum3, 3); if (loopData.ExtraTemp3 < 255) { - ExtraDewPoint[3] = ConvertTempCToUser(MeteoLib.DewPoint(ConvertUserTempToC(ExtraTemp[3]), ExtraHum[3])); + ExtraDewPoint[3] = ConvertUnits.TempCToUser(MeteoLib.DewPoint(ConvertUnits.UserTempToC(ExtraTemp[3]), ExtraHum[3])); } } @@ -1738,7 +1738,7 @@ private void GetAndProcessLoopData(int number) DoExtraHum(loopData.ExtraHum4, 4); if (loopData.ExtraTemp4 < 255) { - ExtraDewPoint[4] = ConvertTempCToUser(MeteoLib.DewPoint(ConvertUserTempToC(ExtraTemp[4]), ExtraHum[4])); + ExtraDewPoint[4] = ConvertUnits.TempCToUser(MeteoLib.DewPoint(ConvertUnits.UserTempToC(ExtraTemp[4]), ExtraHum[4])); } } @@ -1779,22 +1779,22 @@ private void GetAndProcessLoopData(int number) if (loopData.SoilTemp1 < 255 && loopData.SoilTemp1 > 0) { - DoSoilTemp(ConvertTempFToUser(loopData.SoilTemp1 - 90), 1); + DoSoilTemp(ConvertUnits.TempFToUser(loopData.SoilTemp1 - 90), 1); } if (loopData.SoilTemp2 < 255 && loopData.SoilTemp2 > 0) { - DoSoilTemp(ConvertTempFToUser(loopData.SoilTemp2 - 90), 2); + DoSoilTemp(ConvertUnits.TempFToUser(loopData.SoilTemp2 - 90), 2); } if (loopData.SoilTemp3 < 255 && loopData.SoilTemp3 > 0) { - DoSoilTemp(ConvertTempFToUser(loopData.SoilTemp3 - 90), 3); + DoSoilTemp(ConvertUnits.TempFToUser(loopData.SoilTemp3 - 90), 3); } if (loopData.SoilTemp4 < 255 && loopData.SoilTemp4 > 0) { - DoSoilTemp(ConvertTempFToUser(loopData.SoilTemp4 - 90), 4); + DoSoilTemp(ConvertUnits.TempFToUser(loopData.SoilTemp4 - 90), 4); } if (loopData.LeafWetness1 >= 0 && loopData.LeafWetness1 < 16) @@ -1968,13 +1968,13 @@ private void GetAndProcessLoop2Data(int number) else { // Spike removal is in mb/hPa - var pressUser = ConvertPressINHGToUser(loopData.AbsolutePressure); - var pressMB = ConvertUserPressToMB(pressUser); + var pressUser = ConvertUnits.PressINHGToUser(loopData.AbsolutePressure); + var pressMB = ConvertUnits.UserPressToMB(pressUser); if ((previousPressStation == 9999) || (Math.Abs(pressMB - previousPressStation) < cumulus.Spike.PressDiff)) { previousPressStation = pressMB; - StationPressure = ConvertPressINHGToUser(loopData.AbsolutePressure); - AltimeterPressure = ConvertPressMBToUser(StationToAltimeter(ConvertUserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); + StationPressure = ConvertUnits.PressINHGToUser(loopData.AbsolutePressure); + AltimeterPressure = ConvertUnits.PressMBToUser(StationToAltimeter(ConvertUnits.UserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); } else { @@ -1986,7 +1986,7 @@ private void GetAndProcessLoop2Data(int number) } } - double wind = ConvertWindMPHToUser(loopData.CurrentWindSpeed); + double wind = ConvertUnits.WindMPHToUser(loopData.CurrentWindSpeed); // Use current average as we don't have a new value in LOOP2. Allow for calibration. if (loopData.CurrentWindSpeed < 200) @@ -2002,7 +2002,7 @@ private void GetAndProcessLoop2Data(int number) if (loopData.WindGust10Min < 200 && cumulus.StationOptions.PeakGustMinutes >= 10) { // Extract 10-min gust and see if it is higher than we have recorded. - var rawGust10min = ConvertWindMPHToUser(loopData.WindGust10Min); + var rawGust10min = ConvertUnits.WindMPHToUser(loopData.WindGust10Min); var gust10min = cumulus.Calib.WindGust.Calibrate(rawGust10min); var gustdir = (int)cumulus.Calib.WindDir.Calibrate(loopData.WindGustDir); @@ -2025,7 +2025,7 @@ private void GetAndProcessLoop2Data(int number) if (loopData.THSWindex < 32000) { - THSWIndex = ConvertTempFToUser(loopData.THSWindex); + THSWIndex = ConvertUnits.TempFToUser(loopData.THSWindex); } //UpdateStatusPanel(DateTime.Now); @@ -2447,7 +2447,7 @@ private void GetArchiveData() if ((archiveData.InsideTemperature > -200) && (archiveData.InsideTemperature < 300)) { - DoIndoorTemp(ConvertTempFToUser(archiveData.InsideTemperature)); + DoIndoorTemp(ConvertUnits.TempFToUser(archiveData.InsideTemperature)); } if ((archiveData.InsideHumidity >= 0) && (archiveData.InsideHumidity <= 100)) @@ -2463,19 +2463,19 @@ private void GetArchiveData() // Check if the archive hi/lo temps break any records if ((archiveData.HiOutsideTemp > -200) && (archiveData.HiOutsideTemp < 300)) { - DoOutdoorTemp(ConvertTempFToUser(archiveData.HiOutsideTemp), timestamp); + DoOutdoorTemp(ConvertUnits.TempFToUser(archiveData.HiOutsideTemp), timestamp); } // Check if the archive hi/lo temps break any records if ((archiveData.LoOutsideTemp > -200) && (archiveData.LoOutsideTemp < 300)) { - DoOutdoorTemp(ConvertTempFToUser(archiveData.LoOutsideTemp), timestamp); + DoOutdoorTemp(ConvertUnits.TempFToUser(archiveData.LoOutsideTemp), timestamp); } // Now process the "average" interval temperature - use this as our if ((archiveData.OutsideTemperature > -200) && (archiveData.OutsideTemperature < 300)) { - DoOutdoorTemp(ConvertTempFToUser(archiveData.OutsideTemperature), timestamp); + DoOutdoorTemp(ConvertUnits.TempFToUser(archiveData.OutsideTemperature), timestamp); // add in 'archivePeriod' minutes worth of temperature to the temp samples tempsamplestoday += interval; TempTotalToday += (OutdoorTemperature * interval); @@ -2491,8 +2491,8 @@ private void GetArchiveData() UpdateDegreeDays(interval); } - double wind = ConvertWindMPHToUser(archiveData.HiWindSpeed); - double avgwind = ConvertWindMPHToUser(archiveData.AvgWindSpeed); + double wind = ConvertUnits.WindMPHToUser(archiveData.HiWindSpeed); + double avgwind = ConvertUnits.WindMPHToUser(archiveData.AvgWindSpeed); if (archiveData.HiWindSpeed < 250 && archiveData.AvgWindSpeed < 250) { int bearing = archiveData.WindDirection; @@ -2528,7 +2528,7 @@ private void GetArchiveData() CheckForWindrunHighLow(windruncheckTS); - double rain = ConvertRainClicksToUser(archiveData.Rainfall) + Raincounter; + double rain = ConvertRainClicksToUser(archiveData.Rainfall) + RainCounter; double rainrate = ConvertRainClicksToUser(archiveData.HiRainRate); if (rainrate < 0) @@ -2540,7 +2540,7 @@ private void GetArchiveData() if ((archiveData.Pressure > 0) && (archiveData.Pressure < 40)) { - DoPressure(ConvertPressINHGToUser(archiveData.Pressure), timestamp); + DoPressure(ConvertUnits.PressINHGToUser(archiveData.Pressure), timestamp); } if (archiveData.HiUVIndex >= 0 && archiveData.HiUVIndex < 25) @@ -2559,24 +2559,24 @@ private void GetArchiveData() if (!cumulus.StationOptions.CalculatedET && archiveData.ET >= 0 && archiveData.ET < 32000) { - DoET(ConvertRainINToUser(archiveData.ET) + AnnualETTotal, timestamp); + DoET(ConvertUnits.RainINToUser(archiveData.ET) + AnnualETTotal, timestamp); } if (cumulus.StationOptions.LogExtraSensors) { if (archiveData.ExtraTemp1 < 255) { - DoExtraTemp(ConvertTempFToUser(archiveData.ExtraTemp1 - 90), 1); + DoExtraTemp(ConvertUnits.TempFToUser(archiveData.ExtraTemp1 - 90), 1); } if (archiveData.ExtraTemp2 < 255) { - DoExtraTemp(ConvertTempFToUser(archiveData.ExtraTemp2 - 90), 2); + DoExtraTemp(ConvertUnits.TempFToUser(archiveData.ExtraTemp2 - 90), 2); } if (archiveData.ExtraTemp3 < 255) { - DoExtraTemp(ConvertTempFToUser(archiveData.ExtraTemp3 - 90), 3); + DoExtraTemp(ConvertUnits.TempFToUser(archiveData.ExtraTemp3 - 90), 3); } if (archiveData.ExtraHum1 >= 0 && archiveData.ExtraHum1 <= 100) @@ -2584,7 +2584,7 @@ private void GetArchiveData() DoExtraHum(archiveData.ExtraHum1, 1); if (archiveData.ExtraTemp1 < 255) { - ExtraDewPoint[1] = ConvertTempCToUser(MeteoLib.DewPoint(ConvertUserTempToC(ExtraTemp[1]), ExtraHum[1])); + ExtraDewPoint[1] = ConvertUnits.TempCToUser(MeteoLib.DewPoint(ConvertUnits.UserTempToC(ExtraTemp[1]), ExtraHum[1])); } } @@ -2593,7 +2593,7 @@ private void GetArchiveData() DoExtraHum(archiveData.ExtraHum2, 2); if (archiveData.ExtraTemp2 < 255) { - ExtraDewPoint[2] = ConvertTempCToUser(MeteoLib.DewPoint(ConvertUserTempToC(ExtraTemp[2]), ExtraHum[2])); + ExtraDewPoint[2] = ConvertUnits.TempCToUser(MeteoLib.DewPoint(ConvertUnits.UserTempToC(ExtraTemp[2]), ExtraHum[2])); } } @@ -2619,22 +2619,22 @@ private void GetArchiveData() if (archiveData.SoilTemp1 < 255 && archiveData.SoilTemp1 > 0) { - DoSoilTemp(ConvertTempFToUser(archiveData.SoilTemp1 - 90), 1); + DoSoilTemp(ConvertUnits.TempFToUser(archiveData.SoilTemp1 - 90), 1); } if (archiveData.SoilTemp2 < 255 && archiveData.SoilTemp2 > 0) { - DoSoilTemp(ConvertTempFToUser(archiveData.SoilTemp2 - 90), 2); + DoSoilTemp(ConvertUnits.TempFToUser(archiveData.SoilTemp2 - 90), 2); } if (archiveData.SoilTemp3 < 255 && archiveData.SoilTemp3 > 0) { - DoSoilTemp(ConvertTempFToUser(archiveData.SoilTemp3 - 90), 3); + DoSoilTemp(ConvertUnits.TempFToUser(archiveData.SoilTemp3 - 90), 3); } if (archiveData.SoilTemp4 < 255 && archiveData.SoilTemp4 > 0) { - DoSoilTemp(ConvertTempFToUser(archiveData.SoilTemp4 - 90), 4); + DoSoilTemp(ConvertUnits.TempFToUser(archiveData.SoilTemp4 - 90), 4); } if (archiveData.LeafWetness1 >= 0 && archiveData.LeafWetness1 < 16) @@ -2669,13 +2669,13 @@ private void GetArchiveData() } AddRecentDataEntry(timestamp, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, - OutdoorHumidity, Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate, -1, -1); + OutdoorHumidity, Pressure, RainToday, SolarRad, UV, RainCounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate, -1, -1); DoTrendValues(timestamp); if (cumulus.StationOptions.CalculatedET && timestamp.Minute == 0) { // Start of a new hour, and we want to calculate ET in Cumulus - CalculateEvaoptranspiration(timestamp); + CalculateEvapotranspiration(timestamp); } UpdatePressureTrendString(); @@ -3760,19 +3760,19 @@ private double ConvertRainClicksToUser(double clicks) { case 0: // Rain gauge is metric 0.2 mm - return ConvertRainMMToUser(clicks * 0.2); + return ConvertUnits.RainMMToUser(clicks * 0.2); case 1: // Rain gauge is imperial 0.01 in - return ConvertRainINToUser(clicks * 0.01); + return ConvertUnits.RainINToUser(clicks * 0.01); case 2: // Rain gauge is metric 0.1 mm - return ConvertRainMMToUser(clicks * 0.1); + return ConvertUnits.RainMMToUser(clicks * 0.1); case 3: // Rain gauge is imperial 0.001 in - return ConvertRainMMToUser(clicks * 0.2); + return ConvertUnits.RainMMToUser(clicks * 0.2); default: // Rain gauge type not configured, assume it is the same as the station units diff --git a/CumulusMX/DavisWllStation.cs b/CumulusMX/DavisWllStation.cs index 03da438d..182ec845 100644 --- a/CumulusMX/DavisWllStation.cs +++ b/CumulusMX/DavisWllStation.cs @@ -285,8 +285,8 @@ public override void Start() broadcastTask = Task.Run(async () => { byte[] lastMessage = null; - var endPoint = new IPEndPoint(IPAddress.Any, port); - using (var udpClient = new UdpClient(endPoint)) + //var endPoint = new IPEndPoint(IPAddress.Any, port); + using (var udpClient = new UdpClient(port)) { udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); @@ -372,14 +372,14 @@ public override void Stop() StopMinuteTimer(); try { - if (bw != null && bw.WorkerSupportsCancellation) + if (bw != null && bw.WorkerSupportsCancellation && !bw.CancellationPending) { bw.CancelAsync(); } if (broadcastTask != null) broadcastTask.Wait(); - bwDoneEvent.WaitOne(); + bwDoneEvent.WaitOne(2000); } catch { @@ -585,7 +585,7 @@ private void DecodeBroadcast(string broadcastJson, IPEndPoint from) { // WLL BUG/FEATURE: The WLL sends a null wind direction for calm when the avg speed falls to zero, we use zero var windDir = (int) (rec.wind_dir_last ?? 0); - var spd = ConvertWindMPHToUser(rec.wind_speed_last); + var spd = ConvertUnits.WindMPHToUser(rec.wind_speed_last); // No average in the broadcast data, so use current average. DoWind(spd, windDir, -1, dateTime); @@ -647,7 +647,7 @@ private void DecodeBroadcast(string broadcastJson, IPEndPoint from) else if (broadcastJson.StartsWith("STR_BCAST")) { var msg = broadcastJson.Replace(((char) 0x00), '.').Replace(((char) 0x1c), '.'); - cumulus.LogWarningMessage($"WLL broadcast: Received spurious message from printer utility(?) at IP address {from.Address.ToString()} starting with \"STR_BCAST\""); + cumulus.LogDebugMessage($"WLL broadcast: Received spurious message from printer utility(?) at IP address {from.Address} starting with \"STR_BCAST\""); cumulus.LogDataMessage("WLL broadcast: Message = " + msg); } else @@ -665,7 +665,7 @@ private void DecodeBroadcast(string broadcastJson, IPEndPoint from) multicastsBad++; var msg = string.Format("WLL broadcast: Error processing broadcast. Percentage good packets {0:F2}% - ({1},{2})", (multicastsGood / (float) (multicastsBad + multicastsGood) * 100), multicastsBad, multicastsGood); cumulus.LogErrorMessage(msg); - cumulus.LogMessage($"WLL broadcast: Received from {from.Address.ToString()}: " + broadcastJson); + cumulus.LogMessage($"WLL broadcast: Received from {from.Address}: " + broadcastJson); } } @@ -731,20 +731,20 @@ private void DecodeCurrent(string currentJson) DoOutdoorHumidity(Convert.ToInt32(data1.hum.Value), dateTime); if (data1.temp.HasValue) - DoOutdoorTemp(ConvertTempFToUser(data1.temp.Value), dateTime); + DoOutdoorTemp(ConvertUnits.TempFToUser(data1.temp.Value), dateTime); if (data1.dew_point.HasValue) - DoOutdoorDewpoint(ConvertTempFToUser(data1.dew_point.Value), dateTime); + DoOutdoorDewpoint(ConvertUnits.TempFToUser(data1.dew_point.Value), dateTime); if (!cumulus.StationOptions.CalculatedWC && data1.wind_chill.HasValue) { // use wind chill from WLL - DoWindChill(ConvertTempFToUser(data1.wind_chill.Value), dateTime); + DoWindChill(ConvertUnits.TempFToUser(data1.wind_chill.Value), dateTime); } if (data1.thsw_index.HasValue) { - THSWIndex = ConvertTempFToUser(data1.thsw_index.Value); + THSWIndex = ConvertUnits.TempFToUser(data1.thsw_index.Value); } //TODO: Wet Bulb? rec["wet_bulb"] - No, we already have humidity @@ -774,7 +774,7 @@ private void DecodeCurrent(string currentJson) { cumulus.LogDebugMessage($"WLL current: using extra temp data from TxId {data1.txid}"); - DoExtraTemp(ConvertTempFToUser(data1.temp.Value), tempTxId); + DoExtraTemp(ConvertUnits.TempFToUser(data1.temp.Value), tempTxId); } if (cumulus.WllExtraHumTx[tempTxId] && data1.hum.HasValue) @@ -819,15 +819,15 @@ private void DecodeCurrent(string currentJson) // pesky null values from WLL when it is calm double currentAvgWindSpd; if (cumulus.StationOptions.AvgSpeedMinutes == 1) - currentAvgWindSpd = ConvertWindMPHToUser(data1.wind_speed_avg_last_1_min ?? 0); + currentAvgWindSpd = ConvertUnits.WindMPHToUser(data1.wind_speed_avg_last_1_min ?? 0); else if (cumulus.StationOptions.AvgSpeedMinutes < 10) - currentAvgWindSpd = ConvertWindMPHToUser(data1.wind_speed_avg_last_2_min ?? 0); + currentAvgWindSpd = ConvertUnits.WindMPHToUser(data1.wind_speed_avg_last_2_min ?? 0); else - currentAvgWindSpd = ConvertWindMPHToUser(data1.wind_speed_avg_last_10_min ?? 0); + currentAvgWindSpd = ConvertUnits.WindMPHToUser(data1.wind_speed_avg_last_10_min ?? 0); // pesky null values from WLL when it is calm int wdir = data1.wind_dir_last ?? 0; - double wind = ConvertWindMPHToUser(data1.wind_speed_last ?? 0); + double wind = ConvertUnits.WindMPHToUser(data1.wind_speed_last ?? 0); cumulus.StationOptions.CalcuateAverageWindSpeed = false; CalcRecentMaxGust = false; @@ -840,12 +840,12 @@ private void DecodeCurrent(string currentJson) int gustDir; if (cumulus.StationOptions.PeakGustMinutes <= 10) { - gust = ConvertWindMPHToUser(data1.wind_speed_hi_last_2_min ?? 0); + gust = ConvertUnits.WindMPHToUser(data1.wind_speed_hi_last_2_min ?? 0); gustDir = data1.wind_dir_at_hi_speed_last_2_min ?? 0; } else { - gust = ConvertWindMPHToUser(data1.wind_speed_hi_last_10_min ?? 0); + gust = ConvertUnits.WindMPHToUser(data1.wind_speed_hi_last_10_min ?? 0); gustDir = data1.wind_dir_at_hi_speed_last_10_min ?? 0; } @@ -957,7 +957,7 @@ private void DecodeCurrent(string currentJson) var rain = ConvertRainClicksToUser(data1.rainfall_year.Value, data1.rain_size.Value); var rainrate = ConvertRainClicksToUser(data1.rain_rate_last.Value, data1.rain_size.Value); - if (rain > 0 && rain < Raincounter) + if (rain > 0 && rain < RainCounter) { cumulus.LogDebugMessage("WLL current: The current yearly rainfall value is less than the value we had previously, ignoring it to avoid double counting"); } @@ -1144,7 +1144,7 @@ private void DecodeCurrent(string currentJson) { var val = (double?) data2[idx]; if (val.HasValue) - DoSoilTemp(ConvertTempFToUser(val.Value), 1); + DoSoilTemp(ConvertUnits.TempFToUser(val.Value), 1); } catch (Exception ex) { @@ -1159,7 +1159,7 @@ private void DecodeCurrent(string currentJson) { var val = (double?) data2[idx]; if (val.HasValue) - DoSoilTemp(ConvertTempFToUser(val.Value), 2); + DoSoilTemp(ConvertUnits.TempFToUser(val.Value), 2); } catch (Exception ex) { @@ -1174,7 +1174,7 @@ private void DecodeCurrent(string currentJson) { var val = (double?) data2[idx]; if (val.HasValue) - DoSoilTemp(ConvertTempFToUser(val.Value), 3); + DoSoilTemp(ConvertUnits.TempFToUser(val.Value), 3); } catch (Exception ex) { @@ -1189,7 +1189,7 @@ private void DecodeCurrent(string currentJson) { var val = (double?) data2[idx]; if (val.HasValue) - DoSoilTemp(ConvertTempFToUser(val.Value), 4); + DoSoilTemp(ConvertUnits.TempFToUser(val.Value), 4); } catch (Exception ex) { @@ -1216,14 +1216,14 @@ private void DecodeCurrent(string currentJson) { var data3 = rec.FromJsv(); if (data3.bar_sea_level.HasValue) - DoPressure(ConvertPressINHGToUser(data3.bar_sea_level.Value), dateTime); + DoPressure(ConvertUnits.PressINHGToUser(data3.bar_sea_level.Value), dateTime); // Altimeter from absolute if (data3.bar_absolute.HasValue) { - StationPressure = ConvertPressINHGToUser(data3.bar_absolute.Value); + StationPressure = ConvertUnits.PressINHGToUser(data3.bar_absolute.Value); // Or do we use calibration? The VP2 code doesn't? - //StationPressure = ConvertPressINHGToUser(rec.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; - AltimeterPressure = ConvertPressMBToUser(StationToAltimeter(ConvertUserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); + //StationPressure = ConvertUnits.PressINHGToUser(rec.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; + AltimeterPressure = ConvertUnits.PressMBToUser(StationToAltimeter(ConvertUnits.UserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); } } catch (Exception ex) @@ -1250,7 +1250,7 @@ private void DecodeCurrent(string currentJson) try { if (data4.temp_in.HasValue) - DoIndoorTemp(ConvertTempFToUser(data4.temp_in.Value)); + DoIndoorTemp(ConvertUnits.TempFToUser(data4.temp_in.Value)); } catch (Exception ex) { @@ -1356,13 +1356,13 @@ private double ConvertRainClicksToUser(double clicks, int size) switch (size) { case 1: - return ConvertRainINToUser(clicks * 0.01); + return ConvertUnits.RainINToUser(clicks * 0.01); case 2: - return ConvertRainMMToUser(clicks * 0.2); + return ConvertUnits.RainMMToUser(clicks * 0.2); case 3: - return ConvertRainMMToUser(clicks * 0.1); + return ConvertUnits.RainMMToUser(clicks * 0.1); case 4: - return ConvertRainINToUser(clicks * 0.001); + return ConvertUnits.RainINToUser(clicks * 0.001); default: switch (cumulus.DavisOptions.RainGaugeType) { @@ -1376,9 +1376,9 @@ private double ConvertRainClicksToUser(double clicks, int size) return clicks * 0.01; // Rain gauge is metric, convert to user unit case 0: - return ConvertRainMMToUser(clicks * 0.2); + return ConvertUnits.RainMMToUser(clicks * 0.2); default: - return ConvertRainINToUser(clicks * 0.01); + return ConvertUnits.RainINToUser(clicks * 0.01); } } } @@ -1824,13 +1824,13 @@ private void GetWlHistoricData(BackgroundWorker worker) } AddRecentDataWithAq(timestamp, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, - OutdoorHumidity, Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); + OutdoorHumidity, Pressure, RainToday, SolarRad, UV, RainCounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); DoTrendValues(timestamp); if (cumulus.StationOptions.CalculatedET && timestamp.Minute == 0) { // Start of a new hour, and we want to calculate ET in Cumulus - CalculateEvaoptranspiration(timestamp); + CalculateEvapotranspiration(timestamp); } UpdateStatusPanel(timestamp); @@ -1950,7 +1950,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) if (data11.temp_hi_at != 0 && data11.temp_hi != null) { ts = Utils.FromUnixTime(data11.temp_hi_at); - DoOutdoorTemp(ConvertTempFToUser((double) data11.temp_hi), ts); + DoOutdoorTemp(ConvertUnits.TempFToUser((double) data11.temp_hi), ts); } else { @@ -1961,7 +1961,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) if (data11.temp_lo_at != 0 && data11.temp_lo != null) { ts = Utils.FromUnixTime(data11.temp_lo_at); - DoOutdoorTemp(ConvertTempFToUser((double) data11.temp_lo), ts); + DoOutdoorTemp(ConvertUnits.TempFToUser((double) data11.temp_lo), ts); } else { @@ -1971,11 +1971,11 @@ private void DecodeHistoric(int dataType, int sensorType, string json) // do last temp if (data11.temp_last != null) { - DoOutdoorTemp(ConvertTempFToUser((double) data11.temp_last), recordTs); + DoOutdoorTemp(ConvertUnits.TempFToUser((double) data11.temp_last), recordTs); // set the values for daily average, arch_int is in seconds, but always whole minutes tempsamplestoday += data11.arch_int / 60; - TempTotalToday += ConvertTempFToUser(data11.temp_avg) * data11.arch_int / 60; + TempTotalToday += ConvertUnits.TempFToUser(data11.temp_avg) * data11.arch_int / 60; // update chill hours if (OutdoorTemperature < cumulus.ChillHourThreshold) @@ -2005,7 +2005,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) if (data11.dew_point_hi_at != 0 && data11.dew_point_hi != null) { ts = Utils.FromUnixTime(data11.dew_point_hi_at); - DoOutdoorDewpoint(ConvertTempFToUser((double) data11.dew_point_hi), ts); + DoOutdoorDewpoint(ConvertUnits.TempFToUser((double) data11.dew_point_hi), ts); } else { @@ -2016,7 +2016,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) if (data11.dew_point_lo_at != 0 && data11.dew_point_lo != null) { ts = Utils.FromUnixTime(data11.dew_point_lo_at); - DoOutdoorDewpoint(ConvertTempFToUser((double) data11.dew_point_lo), ts); + DoOutdoorDewpoint(ConvertUnits.TempFToUser((double) data11.dew_point_lo), ts); } else { @@ -2026,7 +2026,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) // do last DP if (data11.dew_point_last != null) { - DoOutdoorDewpoint(ConvertTempFToUser((double) data11.dew_point_last), recordTs); + DoOutdoorDewpoint(ConvertUnits.TempFToUser((double) data11.dew_point_last), recordTs); } else { @@ -2047,7 +2047,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) if (data11.wind_chill_lo_at != 0 && data11.wind_chill_lo != null) { ts = Utils.FromUnixTime(data11.wind_chill_lo_at); - DoWindChill(ConvertTempFToUser((double) data11.wind_chill_lo), ts); + DoWindChill(ConvertUnits.TempFToUser((double) data11.wind_chill_lo), ts); } else { @@ -2057,7 +2057,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) // do last WC if (data11.wind_chill_last != null) { - DoWindChill(ConvertTempFToUser((double) data11.wind_chill_last), recordTs); + DoWindChill(ConvertUnits.TempFToUser((double) data11.wind_chill_last), recordTs); } else { @@ -2086,7 +2086,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) { cumulus.LogDebugMessage($"WL.com historic: using extra temp data from TxId {data11.tx_id}"); - DoExtraTemp(ConvertTempFToUser((double) data11.temp_last), tempTxId); + DoExtraTemp(ConvertUnits.TempFToUser((double) data11.temp_last), tempTxId); } } catch (Exception ex) @@ -2128,8 +2128,8 @@ private void DecodeHistoric(int dataType, int sensorType, string json) { if (data11.wind_speed_hi != null && data11.wind_speed_hi_dir != null && data11.wind_speed_avg != null) { - var gust = ConvertWindMPHToUser((double) data11.wind_speed_hi); - var spd = ConvertWindMPHToUser((double) data11.wind_speed_avg); + var gust = ConvertUnits.WindMPHToUser((double) data11.wind_speed_hi); + var spd = ConvertUnits.WindMPHToUser((double) data11.wind_speed_avg); var dir = data11.wind_speed_hi_dir ?? 0; cumulus.LogDebugMessage($"WL.com historic: using wind data from TxId {data11.tx_id}"); DoWind(gust, dir, spd, recordTs); @@ -2142,7 +2142,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) if (data11.wind_speed_avg != null) { - WindAverage = cumulus.Calib.WindSpeed.Calibrate(ConvertWindMPHToUser((double) data11.wind_speed_avg)); + WindAverage = cumulus.Calib.WindSpeed.Calibrate(ConvertUnits.WindMPHToUser((double) data11.wind_speed_avg)); // add in 'archivePeriod' minutes worth of wind speed to windrun int interval = data11.arch_int / 60; @@ -2190,7 +2190,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) { cumulus.LogDebugMessage($"WL.com historic: Adding rain {rain.ToString(cumulus.RainFormat)}"); } - rain += Raincounter; + rain += RainCounter; if (rainrate < 0) { @@ -2279,8 +2279,8 @@ private void DecodeHistoric(int dataType, int sensorType, string json) // The number is the total for the one hour period. // This is unlike the existing VP2 when the ET is an annual running total // So we try and mimic the VP behaviour - var newET = AnnualETTotal + ConvertRainINToUser((double) data11.et); - cumulus.LogDebugMessage($"WLL DecodeHistoric: Adding {ConvertRainINToUser((double) data11.et):F3} to ET"); + var newET = AnnualETTotal + ConvertUnits.RainINToUser((double) data11.et); + cumulus.LogDebugMessage($"WLL DecodeHistoric: Adding {ConvertUnits.RainINToUser((double) data11.et):F3} to ET"); DoET(newET, recordTs); } } @@ -2465,7 +2465,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) } else { - DoSoilTemp(ConvertTempFToUser((double) data13[idx]), 1); + DoSoilTemp(ConvertUnits.TempFToUser((double) data13[idx]), 1); } } if (cumulus.WllExtraSoilTempTx2 == data13.tx_id) @@ -2477,7 +2477,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) } else { - DoSoilTemp(ConvertTempFToUser((double) data13[idx]), 2); + DoSoilTemp(ConvertUnits.TempFToUser((double) data13[idx]), 2); } } if (cumulus.WllExtraSoilTempTx3 == data13.tx_id) @@ -2489,7 +2489,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) } else { - DoSoilTemp(ConvertTempFToUser((double) data13[idx]), 3); + DoSoilTemp(ConvertUnits.TempFToUser((double) data13[idx]), 3); } } if (cumulus.WllExtraSoilTempTx4 == data13.tx_id) @@ -2501,7 +2501,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) } else { - DoSoilTemp(ConvertTempFToUser((double) data13[idx]), 4); + DoSoilTemp(ConvertUnits.TempFToUser((double) data13[idx]), 4); } } } @@ -2533,7 +2533,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) if (data13baro.bar_hi_at != 0 && data13baro.bar_hi != null) { ts = Utils.FromUnixTime(data13baro.bar_hi_at); - DoPressure(ConvertPressINHGToUser((double) data13baro.bar_hi), ts); + DoPressure(ConvertUnits.PressINHGToUser((double) data13baro.bar_hi), ts); } else { @@ -2543,7 +2543,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) if (data13baro.bar_lo_at != 0 && data13baro.bar_lo != null) { ts = Utils.FromUnixTime(data13baro.bar_lo_at); - DoPressure(ConvertPressINHGToUser((double) data13baro.bar_lo), ts); + DoPressure(ConvertUnits.PressINHGToUser((double) data13baro.bar_lo), ts); } else { @@ -2554,7 +2554,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) { // leave it at current value ts = Utils.FromUnixTime(data13baro.ts); - DoPressure(ConvertPressINHGToUser((double) data13baro.bar_sea_level), ts); + DoPressure(ConvertUnits.PressINHGToUser((double) data13baro.bar_sea_level), ts); } else { @@ -2564,10 +2564,10 @@ private void DecodeHistoric(int dataType, int sensorType, string json) // Altimeter from absolute if (data13baro.bar_absolute != null) { - StationPressure = ConvertPressINHGToUser((double) data13baro.bar_absolute); + StationPressure = ConvertUnits.PressINHGToUser((double) data13baro.bar_absolute); // Or do we use calibration? The VP2 code doesn't? - //StationPressure = ConvertPressINHGToUser(data.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; - AltimeterPressure = ConvertPressMBToUser(StationToAltimeter(ConvertUserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); + //StationPressure = ConvertUnits.PressINHGToUser(data.Value("bar_absolute")) * cumulus.Calib.Press.Mult + cumulus.Calib.Press.Offset; + AltimeterPressure = ConvertUnits.PressMBToUser(StationToAltimeter(ConvertUnits.UserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); } } catch (Exception ex) @@ -2599,7 +2599,7 @@ private void DecodeHistoric(int dataType, int sensorType, string json) { if (data13temp.temp_in_last != null) { - DoIndoorTemp(ConvertTempFToUser((double) data13temp.temp_in_last)); + DoIndoorTemp(ConvertUnits.TempFToUser((double) data13temp.temp_in_last)); } else { @@ -2831,8 +2831,8 @@ private void DecodeWlApiHealth(WlHistorySensor sensor, bool startingup) // The number is the total for the one hour period. // This is unlike the existing VP2 when the ET is an annual running total // So we try and mimic the VP behaviour - var newET = AnnualETTotal + ConvertRainINToUser((double) data.et); - cumulus.LogDebugMessage($"WLL Health: Adding {ConvertRainINToUser((double) data.et):F3} to ET"); + var newET = AnnualETTotal + ConvertUnits.RainINToUser((double) data.et); + cumulus.LogDebugMessage($"WLL Health: Adding {ConvertUnits.RainINToUser((double) data.et):F3} to ET"); DoET(newET, DateTime.Now); } } diff --git a/CumulusMX/EasyWeather.cs b/CumulusMX/EasyWeather.cs index 431da35a..219c09ca 100644 --- a/CumulusMX/EasyWeather.cs +++ b/CumulusMX/EasyWeather.cs @@ -138,27 +138,27 @@ private void EWGetData(object sender, ElapsedEventArgs elapsedEventArgs) lastTime = timestr; } - DoWind(ConvertWindMSToUser(GetConvertedValue(st[EW_WIND_GUST])), CPtoBearing(st[EW_WIND_BEARING_CP]), ConvertWindMSToUser(GetConvertedValue(st[EW_AVERAGE_WIND])), now); + DoWind(ConvertUnits.WindMSToUser(GetConvertedValue(st[EW_WIND_GUST])), CPtoBearing(st[EW_WIND_BEARING_CP]), ConvertUnits.WindMSToUser(GetConvertedValue(st[EW_AVERAGE_WIND])), now); - DoWindChill(ConvertTempCToUser(GetConvertedValue(st[EW_WIND_CHILL])), now); + DoWindChill(ConvertUnits.TempCToUser(GetConvertedValue(st[EW_WIND_CHILL])), now); DoIndoorHumidity(Convert.ToInt32(st[EW_INDOOR_HUM])); DoOutdoorHumidity(Convert.ToInt32(st[EW_OUTDOOR_HUM]), now); - DoOutdoorDewpoint(ConvertTempCToUser(GetConvertedValue(st[EW_DEW_POINT])), now); + DoOutdoorDewpoint(ConvertUnits.TempCToUser(GetConvertedValue(st[EW_DEW_POINT])), now); - DoPressure(ConvertPressMBToUser(GetConvertedValue(st[EW_REL_PRESSURE])), now); + DoPressure(ConvertUnits.PressMBToUser(GetConvertedValue(st[EW_REL_PRESSURE])), now); UpdatePressureTrendString(); - StationPressure = ConvertPressMBToUser(GetConvertedValue(st[EW_ABS_PRESSURE])); + StationPressure = ConvertUnits.PressMBToUser(GetConvertedValue(st[EW_ABS_PRESSURE])); - DoIndoorTemp(ConvertTempCToUser(GetConvertedValue(st[EW_INDOOR_TEMP]))); + DoIndoorTemp(ConvertUnits.TempCToUser(GetConvertedValue(st[EW_INDOOR_TEMP]))); - DoOutdoorTemp(ConvertTempCToUser(GetConvertedValue(st[EW_OUTDOOR_TEMP])), now); + DoOutdoorTemp(ConvertUnits.TempCToUser(GetConvertedValue(st[EW_OUTDOOR_TEMP])), now); - DoRain(ConvertRainMMToUser(GetConvertedValue(st[EW_RAIN_LAST_YEAR])), // use year as total - ConvertRainMMToUser(GetConvertedValue(st[EW_RAIN_LAST_HOUR])), // use last hour as current rate + DoRain(ConvertUnits.RainMMToUser(GetConvertedValue(st[EW_RAIN_LAST_YEAR])), // use year as total + ConvertUnits.RainMMToUser(GetConvertedValue(st[EW_RAIN_LAST_HOUR])), // use last hour as current rate now); DoApparentTemp(now); @@ -201,7 +201,7 @@ private void EWGetData(object sender, ElapsedEventArgs elapsedEventArgs) if (cumulus.StationOptions.CalculatedET && now.Minute == 0) { // Start of a new hour, and we want to calculate ET in Cumulus - CalculateEvaoptranspiration(now); + CalculateEvapotranspiration(now); } UpdateStatusPanel(now); diff --git a/CumulusMX/EcowittApi.cs b/CumulusMX/EcowittApi.cs index 8ae34565..8f65c739 100644 --- a/CumulusMX/EcowittApi.cs +++ b/CumulusMX/EcowittApi.cs @@ -26,6 +26,9 @@ internal class EcowittApi private DateTime LastCameraImageTime = DateTime.MinValue; private DateTime LastCameraCallTime = DateTime.MinValue; + private string LastCameraVideoTime = ""; + private DateTime LastCameraVideoCallTime = DateTime.MinValue; + public EcowittApi(Cumulus cuml, WeatherStation stn) { cumulus = cuml; @@ -330,14 +333,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || item.Value == 140 || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].IndoorTemp = item.Value; + value.IndoorTemp = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.IndoorTemp = item.Value; + var newItem = new EcowittApi.HistoricData() + { IndoorTemp = item.Value }; buffer.Add(itemDate, newItem); } } @@ -352,14 +355,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].IndoorHum = item.Value; + value.IndoorHum = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.IndoorHum = item.Value; + var newItem = new EcowittApi.HistoricData() + { IndoorHum = item.Value }; buffer.Add(itemDate, newItem); } } @@ -386,14 +389,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || item.Value == 140 || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].Temp = item.Value; + value.Temp = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.Temp = item.Value; + var newItem = new EcowittApi.HistoricData() + { Temp = item.Value }; buffer.Add(itemDate, newItem); } } @@ -409,14 +412,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].Humidity = item.Value; + value.Humidity = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.Humidity = item.Value; + var newItem = new EcowittApi.HistoricData() + { Humidity = item.Value }; buffer.Add(itemDate, newItem); } } @@ -432,14 +435,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].DewPoint = item.Value; + value.DewPoint = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.DewPoint = item.Value; + var newItem = new EcowittApi.HistoricData() + { DewPoint = item.Value }; buffer.Add(itemDate, newItem); } } @@ -465,14 +468,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].WindSpd = item.Value; + value.WindSpd = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.WindSpd = item.Value; + var newItem = new EcowittApi.HistoricData() + { WindSpd = item.Value }; buffer.Add(itemDate, newItem); } } @@ -488,14 +491,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].WindGust = item.Value; + value.WindGust = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.WindGust = item.Value; + var newItem = new EcowittApi.HistoricData() + { WindGust = item.Value }; buffer.Add(itemDate, newItem); } } @@ -511,14 +514,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].WindDir = item.Value; + value.WindDir = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.WindDir = item.Value; + var newItem = new EcowittApi.HistoricData() + { WindDir = item.Value }; buffer.Add(itemDate, newItem); } } @@ -544,14 +547,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].Pressure = item.Value; + value.Pressure = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.Pressure = item.Value; + var newItem = new EcowittApi.HistoricData() + { Pressure = item.Value}; buffer.Add(itemDate, newItem); } } @@ -579,14 +582,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate < cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].RainRate = item.Value; + value.RainRate = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.RainRate = item.Value; + var newItem = new EcowittApi.HistoricData() + { RainRate = item.Value }; buffer.Add(itemDate, newItem); } } @@ -602,14 +605,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate < cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].RainYear = item.Value; + value.RainYear = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.RainYear = item.Value; + var newItem = new EcowittApi.HistoricData() + { RainYear = item.Value }; buffer.Add(itemDate, newItem); } } @@ -627,14 +630,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate < cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].RainRate = item.Value; + value.RainRate = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.RainRate = item.Value; + var newItem = new EcowittApi.HistoricData() + { RainRate = item.Value }; buffer.Add(itemDate, newItem); } } @@ -650,14 +653,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate < cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].RainYear = item.Value; + value.RainYear = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.RainYear = item.Value; + var newItem = new EcowittApi.HistoricData() + { RainYear = item.Value }; buffer.Add(itemDate, newItem); } } @@ -684,14 +687,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].Solar = (int) item.Value; + value.Solar = (int) item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.Solar = (int) item.Value; + var newItem = new EcowittApi.HistoricData() + { Solar = (int) item.Value }; buffer.Add(itemDate, newItem); } } @@ -707,14 +710,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].UVI = (int) item.Value; + value.UVI = (int) item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.UVI = (int) item.Value; + var newItem = new EcowittApi.HistoricData() + { UVI = (int) item.Value }; buffer.Add(itemDate, newItem); } } @@ -799,9 +802,9 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].ExtraTemp[i] = item.Value; + value.ExtraTemp[i] = item.Value; } else { @@ -822,9 +825,9 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].ExtraHumidity[i] = item.Value; + value.ExtraHumidity[i] = item.Value; } else { @@ -854,9 +857,9 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].SoilMoist[i] = item.Value; + value.SoilMoist[i] = item.Value; } else { @@ -884,9 +887,9 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].UserTemp[i] = item.Value; + value.UserTemp[i] = item.Value; } else { @@ -914,9 +917,9 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].LeafWetness[i] = item.Value; + value.LeafWetness[i] = item.Value; } else { @@ -947,14 +950,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].IndoorCo2 = item.Value; + value.IndoorCo2 = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.IndoorCo2 = item.Value; + var newItem = new EcowittApi.HistoricData() + { IndoorCo2 = item.Value }; buffer.Add(itemDate, newItem); } } @@ -970,14 +973,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].IndoorCo2hr24 = item.Value; + value.IndoorCo2hr24 = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.IndoorCo2hr24 = item.Value; + var newItem = new EcowittApi.HistoricData() + { IndoorCo2hr24 = item.Value }; buffer.Add(itemDate, newItem); } } @@ -1003,14 +1006,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].CO2pm2p5 = item.Value; + value.CO2pm2p5 = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.CO2pm2p5 = item.Value; + var newItem = new EcowittApi.HistoricData() + { CO2pm2p5 = item.Value }; buffer.Add(itemDate, newItem); } } @@ -1026,14 +1029,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].CO2pm2p5hr24 = item.Value; + value.CO2pm2p5hr24 = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.CO2pm2p5hr24 = item.Value; + var newItem = new EcowittApi.HistoricData() + { CO2pm2p5hr24 = item.Value }; buffer.Add(itemDate, newItem); } } @@ -1058,14 +1061,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].AqiComboPm25 = item.Value; + value.AqiComboPm25 = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.AqiComboPm25 = item.Value; + var newItem = new EcowittApi.HistoricData() + { AqiComboPm25 = item.Value }; buffer.Add(itemDate, newItem); } } @@ -1090,14 +1093,14 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].AqiComboPm10 = item.Value; + value.AqiComboPm10 = item.Value; } else { - var newItem = new EcowittApi.HistoricData(); - newItem.AqiComboPm10 = item.Value; + var newItem = new EcowittApi.HistoricData() + { AqiComboPm10 = item.Value }; buffer.Add(itemDate, newItem); } } @@ -1139,9 +1142,9 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke if (!item.Value.HasValue || itemDate <= cumulus.LastUpdateTime) continue; - if (buffer.ContainsKey(itemDate)) + if (buffer.TryGetValue(itemDate, out var value)) { - buffer[itemDate].pm25[i] = item.Value; + value.pm25[i] = item.Value; } else { @@ -1245,12 +1248,12 @@ private void ProcessHistoryData(EcowittHistoricData data, CancellationToken toke // OutdoorHumidity, Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex); station.AddRecentDataWithAq(rec.Key, station.WindAverage, station.RecentMaxGust, station.WindLatest, station.Bearing, station.AvgBearing, station.OutdoorTemperature, station.WindChill, station.OutdoorDewpoint, station.HeatIndex, - station.OutdoorHumidity, station.Pressure, station.RainToday, station.SolarRad, station.UV, station.Raincounter, station.FeelsLike, station.Humidex, station.ApparentTemperature, station.IndoorTemperature, station.IndoorHumidity, station.CurrentSolarMax, station.RainRate); + station.OutdoorHumidity, station.Pressure, station.RainToday, station.SolarRad, station.UV, station.RainCounter, station.FeelsLike, station.Humidex, station.ApparentTemperature, station.IndoorTemperature, station.IndoorHumidity, station.CurrentSolarMax, station.RainRate); if (cumulus.StationOptions.CalculatedET && rec.Key.Minute == 0) { // Start of a new hour, and we want to calculate ET in Cumulus - station.CalculateEvaoptranspiration(rec.Key); + station.CalculateEvapotranspiration(rec.Key); } station.DoTrendValues(rec.Key); @@ -1664,7 +1667,7 @@ private void ApplyHistoricData(KeyValuePair rec) // returns the data structure and the number of seconds to wait before the next update - internal CurrentDataData GetCurrentData(CancellationToken token, ref int delay) + internal CurrentDataData GetCurrentData(ref int delay, CancellationToken token) { // Doc: https://doc.ecowitt.net/web/#/apiv3en?page_id=17 @@ -1851,7 +1854,7 @@ internal CurrentDataData GetCurrentData(CancellationToken token, ref int delay) } - internal string GetCurrentCameraImageUrl(CancellationToken token, string defaultUrl) + internal string GetCurrentCameraImageUrl(string defaultUrl, CancellationToken token) { // Doc: https://doc.ecowitt.net/web/#/apiv3en?page_id=17 @@ -1935,8 +1938,19 @@ internal string GetCurrentCameraImageUrl(CancellationToken token, string default if (currObj.data == null) { // There was no data returned. + cumulus.LogWarningMessage("API.GetCurrentCameraImageUrl: Ecowitt API Current Camera Data: No camera data was returned."); return defaultUrl; } + + if (currObj.data.camera == null) + { + cumulus.LogWarningMessage("API.GetCurrentCameraImageUrl: Ecowitt API Current Camera Data: No camera data was returned."); + return defaultUrl; + } + + LastCameraImageTime = Utils.FromUnixTime(currObj.data.camera.photo.time); + cumulus.LogDebugMessage($"API.GetCurrentCameraImageUrl: Last image update {LastCameraImageTime:s}"); + return currObj.data.camera.photo.url; } else if (currObj.code == -1 || currObj.code == 45001) { @@ -1962,25 +1976,172 @@ internal string GetCurrentCameraImageUrl(CancellationToken token, string default cumulus.LogDataMessage("API.GetCurrentCameraImageUrl: Received: " + responseBody); return defaultUrl; } + } + catch (Exception ex) + { + cumulus.LogErrorMessage("API.GetCurrentCameraImageUrl: Exception: " + ex.Message); + return defaultUrl; + } + } - if (!token.IsCancellationRequested) + internal string GetLastCameraVideoUrl(string defaultUrl, CancellationToken token) + { + // Doc: https://doc.ecowitt.net/web/#/apiv3en?page_id=19 + + /* { - if (currObj.data.camera == null) - { - cumulus.LogWarningMessage("API.GetCurrentCameraImageUrl: Ecowitt API Current Camera Data: No camera data was returned."); - return defaultUrl; + "code": 0, + "msg": "success", + "time": "1701950253", + "data": { + "camera": { + "20231206": { + "video": "https://osswww.ecowitt.net/videos/webvideo/v0/2023_12_06/158185/29f0493644eb87ef7a0ffea30221605c.mp4" + } + } } - - LastCameraImageTime = Utils.FromUnixTime(currObj.data.camera.photo.time); - cumulus.LogDebugMessage($"API.GetCurrentCameraImageUrl: Last image update {LastCameraImageTime:s}"); - return currObj.data.camera.photo.url; } + */ + cumulus.LogMessage("API.GetLastCameraVideoUrl: Get Ecowitt Last Camera Video"); + + if (string.IsNullOrEmpty(cumulus.EcowittApplicationKey) || string.IsNullOrEmpty(cumulus.EcowittUserApiKey) || string.IsNullOrEmpty(cumulus.EcowittCameraMacAddress)) + { + cumulus.LogWarningMessage("API.GetLastCameraVideoUrl: Missing Ecowitt API data in the configuration, aborting!"); + return defaultUrl; + } + // do we already have the latest video + if (LastCameraVideoTime == DateTime.Now.Date.AddDays(-1).ToString("yyyyMMdd")) + { + cumulus.LogMessage("API.GetLastCameraVideoUrl: The video we have is still current"); return defaultUrl; } + + // rate limit to one call per minute + if (LastCameraVideoCallTime.AddMinutes(1) > DateTime.Now) + { + cumulus.LogMessage("API.GetCurrentCameraImageUrl: Last call was less than 1 minute ago, using last video URL"); + return defaultUrl; + } + + + var sb = new StringBuilder(historyUrl); + var end = DateTime.Now.Date; + var start = end.AddDays(-1); + end = end.AddMinutes(-1); + + sb.Append($"application_key={cumulus.EcowittApplicationKey}"); + sb.Append($"&api_key={cumulus.EcowittUserApiKey}"); + sb.Append($"&mac={cumulus.EcowittCameraMacAddress}"); + sb.Append($"&start_date={start:yyyy-MM-dd'%20'HH:mm:ss}"); + sb.Append($"&end_date={end:yyyy-MM-dd'%20'HH:mm:ss}"); + sb.Append("&call_back=camera.video"); + + var url = sb.ToString(); + + var logUrl = url.Replace(cumulus.EcowittApplicationKey, "<>").Replace(cumulus.EcowittUserApiKey, "<>"); + cumulus.LogDebugMessage($"Ecowitt URL = {logUrl}"); + + + try + { + string responseBody; + int responseCode; + + // we want to do this synchronously, so .Result + using (var response = Cumulus.MyHttpClient.GetAsync(url).Result) + { + responseBody = response.Content.ReadAsStringAsync().Result; + responseCode = (int) response.StatusCode; + cumulus.LogDebugMessage($"API.GetLastCameraVideoUrl: Ecowitt API Current Camera Response code: {responseCode}"); + cumulus.LogDataMessage($"API.GetLastCameraVideoUrl: Ecowitt API Current Camera Response: {responseBody}"); + } + + if (responseCode != 200) + { + var currentError = responseBody.FromJson(); + cumulus.LogWarningMessage($"API.GetLastCameraVideoUrl: Ecowitt API Current Camera Error: {currentError.code}, {currentError.msg}"); + cumulus.LogConsoleMessage($" - Error {currentError.code}: {currentError.msg}", ConsoleColor.Red); + return defaultUrl; + } + + + dynamic vidObj = null; + + if (responseBody == "{}") + { + cumulus.LogWarningMessage("API.GetLastCameraVideoUrl: Ecowitt API Current Camera Data: No data was returned."); + cumulus.LogConsoleMessage(" - No current data available"); + return defaultUrl; + } + else if (responseBody.StartsWith("{\"code\":")) // sanity check + { + // get the sensor data + vidObj = DynamicJson.Deserialize(responseBody); + + if (vidObj != null) + { + // success + if (vidObj.code == "0") + { + if (vidObj.data == null) + { + // There was no data returned. + cumulus.LogWarningMessage("API.GetLastCameraVideoUrl: Ecowitt API Current Camera Data: No camera data was returned."); + return defaultUrl; + } + + if (vidObj.data.camera == null) + { + cumulus.LogWarningMessage("API.GetLastCameraVideoUrl: Ecowitt API Current Camera Data: No camera data was returned."); + return defaultUrl; + } + + var found = System.Text.RegularExpressions.Regex.Match(vidObj.data.camera.ToString(), "https.*mp4"); + + if (found.Success) + { + var link = found.Groups[0].Value.Replace("\\", ""); + + LastCameraVideoTime = start.ToString("yyyyMMdd"); + + cumulus.LogDebugMessage($"API.GetLastCameraVideoUrl: Last image update {LastCameraVideoTime:s}, link = {link}"); + return link; + } + else + { + cumulus.LogWarningMessage("API.GetLastCameraVideoUrl: Failed to find URL"); + return defaultUrl; + } + } + else if (vidObj.code == "-1" || vidObj.code == "45001") + { + // -1 = system busy, 45001 = rate limited + + cumulus.LogMessage("API.GetLastCameraVideoUrl: System Busy or Rate Limited, waiting 5 secs before retry..."); + return defaultUrl; + } + else + { + cumulus.LogMessage($"API.GetLastCameraVideoUrl: Unknown error: {vidObj.code} - {vidObj.msg}"); + return defaultUrl; + } + } + else + { + return defaultUrl; + } + } + else // No idea what we got, dump it to the log + { + cumulus.LogErrorMessage("API.GetLastCameraVideoUrl: Invalid message received"); + cumulus.LogDataMessage("API.GetLastCameraVideoUrl: Received: " + responseBody); + return defaultUrl; + } + } catch (Exception ex) { - cumulus.LogErrorMessage("API.GetCurrentData: Exception: " + ex.Message); + cumulus.LogErrorMessage("API.GetLastCameraVideoUrl: Exception: " + ex.Message); return defaultUrl; } } @@ -2340,8 +2501,6 @@ public HistoricData() } - - private class CurrentData { public int code { get; set; } diff --git a/CumulusMX/EcowittCloudStation.cs b/CumulusMX/EcowittCloudStation.cs index ffb0fccd..fc275c2b 100644 --- a/CumulusMX/EcowittCloudStation.cs +++ b/CumulusMX/EcowittCloudStation.cs @@ -14,7 +14,7 @@ internal class EcowittCloudStation : WeatherStation private readonly bool main; - public EcowittCloudStation(Cumulus cumulus, WeatherStation station = null) : base(cumulus) + public EcowittCloudStation(Cumulus cumulus, WeatherStation station = null) : base(cumulus, station != null) { this.station = station; @@ -142,7 +142,7 @@ public override void Start() try { - var data = ecowittApi.GetCurrentData(cumulus.cancellationToken, ref delay); + var data = ecowittApi.GetCurrentData(ref delay, cumulus.cancellationToken); if (data != null) { @@ -205,16 +205,34 @@ public override void getAndProcessHistoryData() public override string GetEcowittCameraUrl() { - if ((cumulus.EcowittExtraUseCamera || main) && cumulus.EcowittCameraMacAddress != null) + if ((cumulus.EcowittExtraUseCamera || main) && !string.IsNullOrEmpty(cumulus.EcowittCameraMacAddress)) { try { - EcowittCameraUrl = ecowittApi.GetCurrentCameraImageUrl(cumulus.cancellationToken, EcowittCameraUrl); + EcowittCameraUrl = ecowittApi.GetCurrentCameraImageUrl(EcowittCameraUrl, cumulus.cancellationToken); return EcowittCameraUrl; } catch (Exception ex) { - cumulus.LogExceptionMessage(ex, "Error runing Ecowitt Camera URL"); + cumulus.LogExceptionMessage(ex, "Error running Ecowitt Camera URL"); + } + } + + return null; + } + + public override string GetEcowittVideoUrl() + { + if ((cumulus.EcowittExtraUseCamera || main) && !string.IsNullOrEmpty(cumulus.EcowittCameraMacAddress)) + { + try + { + EcowittVideoUrl = ecowittApi.GetLastCameraVideoUrl(EcowittVideoUrl, cumulus.cancellationToken); + return EcowittVideoUrl; + } + catch (Exception ex) + { + cumulus.LogExceptionMessage(ex, "Error running Ecowitt Video URL"); } } @@ -553,8 +571,8 @@ private void ProcessExtraTempHum(EcowittApi.CurrentDataData data, WeatherStation station.DoExtraTemp(data.temp_and_humidity_ch1.temperature.value, 1); station.DoExtraHum(data.temp_and_humidity_ch1.humidity.value, 1); - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[1]), station.ExtraHum[1]); - station.ExtraDewPoint[1] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[1]), station.ExtraHum[1]); + station.ExtraDewPoint[1] = ConvertUnits.TempCToUser(dp); } if (data.temp_and_humidity_ch2 != null) @@ -567,8 +585,8 @@ private void ProcessExtraTempHum(EcowittApi.CurrentDataData data, WeatherStation station.DoExtraTemp(data.temp_and_humidity_ch2.temperature.value, 2); station.DoExtraHum(data.temp_and_humidity_ch2.humidity.value, 2); - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[2]), station.ExtraHum[2]); - station.ExtraDewPoint[2] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[2]), station.ExtraHum[2]); + station.ExtraDewPoint[2] = ConvertUnits.TempCToUser(dp); } if (data.temp_and_humidity_ch3 != null) @@ -581,8 +599,8 @@ private void ProcessExtraTempHum(EcowittApi.CurrentDataData data, WeatherStation station.DoExtraTemp(data.temp_and_humidity_ch3.temperature.value, 3); station.DoExtraHum(data.temp_and_humidity_ch3.humidity.value, 3); - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[3]), station.ExtraHum[3]); - station.ExtraDewPoint[3] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[3]), station.ExtraHum[3]); + station.ExtraDewPoint[3] = ConvertUnits.TempCToUser(dp); } if (data.temp_and_humidity_ch4 != null) @@ -595,8 +613,8 @@ private void ProcessExtraTempHum(EcowittApi.CurrentDataData data, WeatherStation station.DoExtraTemp(data.temp_and_humidity_ch4.temperature.value, 4); station.DoExtraHum(data.temp_and_humidity_ch4.humidity.value, 4); - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[4]), station.ExtraHum[4]); - station.ExtraDewPoint[4] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[4]), station.ExtraHum[4]); + station.ExtraDewPoint[4] = ConvertUnits.TempCToUser(dp); } if (data.temp_and_humidity_ch5 != null) @@ -609,8 +627,8 @@ private void ProcessExtraTempHum(EcowittApi.CurrentDataData data, WeatherStation station.DoExtraTemp(data.temp_and_humidity_ch5.temperature.value, 5); station.DoExtraHum(data.temp_and_humidity_ch5.humidity.value, 5); - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[5]), station.ExtraHum[5]); - station.ExtraDewPoint[5] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[5]), station.ExtraHum[5]); + station.ExtraDewPoint[5] = ConvertUnits.TempCToUser(dp); } if (data.temp_and_humidity_ch6 != null) @@ -623,8 +641,8 @@ private void ProcessExtraTempHum(EcowittApi.CurrentDataData data, WeatherStation station.DoExtraTemp(data.temp_and_humidity_ch6.temperature.value, 6); station.DoExtraHum(data.temp_and_humidity_ch6.humidity.value, 6); - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[6]), station.ExtraHum[6]); - station.ExtraDewPoint[6] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[6]), station.ExtraHum[6]); + station.ExtraDewPoint[6] = ConvertUnits.TempCToUser(dp); } if (data.temp_and_humidity_ch7 != null) @@ -637,8 +655,8 @@ private void ProcessExtraTempHum(EcowittApi.CurrentDataData data, WeatherStation station.DoExtraTemp(data.temp_and_humidity_ch7.temperature.value, 7); station.DoExtraHum(data.temp_and_humidity_ch7.humidity.value, 7); - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[7]), station.ExtraHum[7]); - station.ExtraDewPoint[7] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[7]), station.ExtraHum[7]); + station.ExtraDewPoint[7] = ConvertUnits.TempCToUser(dp); } if (data.temp_and_humidity_ch8 != null) @@ -651,8 +669,8 @@ private void ProcessExtraTempHum(EcowittApi.CurrentDataData data, WeatherStation station.DoExtraTemp(data.temp_and_humidity_ch8.temperature.value, 8); station.DoExtraHum(data.temp_and_humidity_ch8.humidity.value, 8); - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[8]), station.ExtraHum[8]); - station.ExtraDewPoint[8] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[8]), station.ExtraHum[8]); + station.ExtraDewPoint[8] = ConvertUnits.TempCToUser(dp); } } @@ -888,7 +906,7 @@ private void ProcessLightning(EcowittApi.CurrentDataData data, WeatherStation st if (data.lightning.distance != null && data.lightning.distance.value != 255) { station.LightningStrikesToday = data.lightning.count.value; - station.LightningDistance = ConvertKmtoUserUnits(data.lightning.distance.value); + station.LightningDistance = ConvertUnits.KmtoUserUnits(data.lightning.distance.value); var tim = Utils.FromUnixTime(data.lightning.distance.time); diff --git a/CumulusMX/FOStation.cs b/CumulusMX/FOStation.cs index c4d60fc1..1311ecc2 100644 --- a/CumulusMX/FOStation.cs +++ b/CumulusMX/FOStation.cs @@ -442,7 +442,7 @@ private void ProcessHistoryData() } else { - DoIndoorTemp(ConvertTempCToUser(historydata.inTemp)); + DoIndoorTemp(ConvertUnits.TempCToUser(historydata.inTemp)); } // Pressure ============================================================= @@ -454,7 +454,7 @@ private void ProcessHistoryData() } else { - DoPressure(ConvertPressMBToUser(historydata.pressure), timestamp); + DoPressure(ConvertUnits.PressMBToUser(historydata.pressure), timestamp); } if (historydata.SensorContactLost) @@ -485,7 +485,7 @@ private void ProcessHistoryData() } else { - DoWind(ConvertWindMSToUser(historydata.windGust), historydata.windBearing, ConvertWindMSToUser(historydata.windSpeed), timestamp); + DoWind(ConvertUnits.WindMSToUser(historydata.windGust), historydata.windBearing, ConvertUnits.WindMSToUser(historydata.windSpeed), timestamp); } // Outdoor Temperature ================================================== @@ -495,7 +495,7 @@ private void ProcessHistoryData() } else { - DoOutdoorTemp(ConvertTempCToUser(historydata.outTemp), timestamp); + DoOutdoorTemp(ConvertUnits.TempCToUser(historydata.outTemp), timestamp); // add in 'archivePeriod' minutes worth of temperature to the temp samples tempsamplestoday += historydata.interval; TempTotalToday += (OutdoorTemperature * historydata.interval); @@ -537,7 +537,7 @@ private void ProcessHistoryData() { if (historydata.interval > 0) { - rainrate = ConvertRainMMToUser((raindiff * 0.3) * (60.0 / historydata.interval)); + rainrate = ConvertUnits.RainMMToUser((raindiff * 0.3) * (60.0 / historydata.interval)); } else { @@ -545,7 +545,7 @@ private void ProcessHistoryData() } } - DoRain(ConvertRainMMToUser(historydata.rainCounter * 0.3), rainrate, timestamp); + DoRain(ConvertUnits.RainMMToUser(historydata.rainCounter * 0.3), rainrate, timestamp); prevraintotal = historydata.rainCounter; @@ -612,13 +612,13 @@ private void ProcessHistoryData() cumulus.MySqlRealtimeFile(999, false, timestamp); AddRecentDataWithAq(timestamp, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, - OutdoorHumidity, Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); + OutdoorHumidity, Pressure, RainToday, SolarRad, UV, RainCounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); DoTrendValues(timestamp); if (cumulus.StationOptions.CalculatedET && timestamp.Minute == 0) { // Start of a new hour, and we want to calculate ET in Cumulus - CalculateEvaoptranspiration(timestamp); + CalculateEvapotranspiration(timestamp); } UpdatePressureTrendString(); @@ -1216,7 +1216,7 @@ private void GetAndProcessData() } else { - DoIndoorTemp(ConvertTempCToUser(intemp)); + DoIndoorTemp(ConvertUnits.TempCToUser(intemp)); } // Pressure ========================================================= @@ -1230,14 +1230,14 @@ private void GetAndProcessData() } else { - DoPressure(ConvertPressMBToUser(pressure), now); + DoPressure(ConvertUnits.PressMBToUser(pressure), now); // Get station pressure in hPa by subtracting offset and calibrating // EWpressure offset is difference between rel and abs in hPa // PressOffset is user calibration in user units. var offsetPress = pressure - pressureOffset; - pressure = offsetPress * offsetPress * cumulus.Calib.Press.Mult2 + offsetPress * cumulus.Calib.Press.Mult + ConvertUserPressureToHPa(cumulus.Calib.Press.Offset); + pressure = offsetPress * offsetPress * cumulus.Calib.Press.Mult2 + offsetPress * cumulus.Calib.Press.Mult + ConvertUnits.UserPressureToHPa(cumulus.Calib.Press.Offset); - StationPressure = ConvertPressMBToUser(pressure); + StationPressure = ConvertUnits.PressMBToUser(pressure); UpdatePressureTrendString(); } @@ -1290,7 +1290,7 @@ private void GetAndProcessData() } else { - DoWind(ConvertWindMSToUser(gust), winddir, ConvertWindMSToUser(windspeed), now); + DoWind(ConvertUnits.WindMSToUser(gust), winddir, ConvertUnits.WindMSToUser(windspeed), now); } // Outdoor Temperature ============================================== @@ -1305,7 +1305,7 @@ private void GetAndProcessData() } else { - DoOutdoorTemp(ConvertTempCToUser(outtemp), now); + DoOutdoorTemp(ConvertUnits.TempCToUser(outtemp), now); // Use current humidity for dewpoint if (OutdoorHumidity > 0) @@ -1343,10 +1343,10 @@ private void GetAndProcessData() if (ignoreraincount == 6) { cumulus.LogMessage("Six consecutive rain readings; accepting value. Adjusting start of day figure to compensate"); - raindaystart += (raindiff * 0.3); + RainCounterDayStart += (raindiff * 0.3); // adjust current rain total counter - Raincounter += (raindiff * 0.3); - cumulus.LogMessage("Setting raindaystart to " + raindaystart); + RainCounter += (raindiff * 0.3); + cumulus.LogMessage("Setting raindaystart to " + RainCounterDayStart); ignoreraincount = 0; } else @@ -1361,7 +1361,7 @@ private void GetAndProcessData() if (ignoreraincount == 0) { - DoRain(ConvertRainMMToUser(raintot * 0.3), -1, now); + DoRain(ConvertUnits.RainMMToUser(raintot * 0.3), -1, now); prevraintotal = raintot; } @@ -1379,7 +1379,7 @@ private void GetAndProcessData() if (UVreading < 0 || UVreading > 16) { - cumulus.LogMessage("Ignoring UV-I reading " + UVreading); + cumulus.LogWarningMessage("Ignoring UV-I reading " + UVreading); } else { diff --git a/CumulusMX/GW1000Api.cs b/CumulusMX/GW1000Api.cs index f054ea62..9a73ffd1 100644 --- a/CumulusMX/GW1000Api.cs +++ b/CumulusMX/GW1000Api.cs @@ -227,7 +227,7 @@ private bool ChecksumOk(byte[] data, int lengthBytes) // sanity check the size if (size + 3 + lengthBytes > data.Length) { - cumulus.LogErrorMessage($"Ckecksum: Error - Calculated data length [{size}] exceeds the buffer size!"); + cumulus.LogErrorMessage($"Checksum: Error - Calculated data length [{size}] exceeds the buffer size!"); return false; } diff --git a/CumulusMX/GW1000Station.cs b/CumulusMX/GW1000Station.cs index f7faa898..a4c1953e 100644 --- a/CumulusMX/GW1000Station.cs +++ b/CumulusMX/GW1000Station.cs @@ -294,11 +294,11 @@ private void GetHistoricData() public override string GetEcowittCameraUrl() { - if (cumulus.EcowittCameraMacAddress != null) + if (!string.IsNullOrEmpty(cumulus.EcowittCameraMacAddress)) { try { - EcowittCameraUrl = ecowittApi.GetCurrentCameraImageUrl(cumulus.cancellationToken, EcowittCameraUrl); + EcowittCameraUrl = ecowittApi.GetCurrentCameraImageUrl(EcowittCameraUrl, cumulus.cancellationToken); return EcowittCameraUrl; } catch (Exception ex) @@ -310,6 +310,25 @@ public override string GetEcowittCameraUrl() return null; } + public override string GetEcowittVideoUrl() + { + if (!string.IsNullOrEmpty(cumulus.EcowittCameraMacAddress)) + { + try + { + EcowittVideoUrl = ecowittApi.GetLastCameraVideoUrl(EcowittVideoUrl, cumulus.cancellationToken); + return EcowittVideoUrl; + } + catch (Exception ex) + { + cumulus.LogExceptionMessage(ex, "Error running Ecowitt Video URL"); + } + } + + return null; + } + + private Discovery DiscoverGW1000() { // We only want unique IP addresses @@ -837,7 +856,7 @@ private void GetLiveData() // do not process temperature here as if "MX calculates DP" is enabled, we have not yet read the humidity value. Have to do it at the end. outdoortemp = tempInt16 / 10.0; } - DoIndoorTemp(ConvertTempCToUser(tempInt16 / 10.0)); + DoIndoorTemp(ConvertUnits.TempCToUser(tempInt16 / 10.0)); idx += 2; break; case 0x02: //Outdoor Temperature (℃) @@ -884,12 +903,12 @@ private void GetLiveData() break; case 0x08: //Absolute Barometric (hPa) tempUint16 = GW1000Api.ConvertBigEndianUInt16(data, idx); - StationPressure = ConvertPressMBToUser(tempUint16 / 10.0); + StationPressure = ConvertUnits.PressMBToUser(tempUint16 / 10.0); idx += 2; break; case 0x09: //Relative Barometric (hPa) tempUint16 = GW1000Api.ConvertBigEndianUInt16(data, idx); - DoPressure(ConvertPressMBToUser(tempUint16 / 10.0), dateTime); + DoPressure(ConvertUnits.PressMBToUser(tempUint16 / 10.0), dateTime); idx += 2; break; case 0x0A: //Wind Direction (360°) @@ -897,24 +916,24 @@ private void GetLiveData() idx += 2; break; case 0x0B: //Wind Speed (m/s) - windSpeedLast = ConvertWindMSToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); + windSpeedLast = ConvertUnits.WindMSToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); idx += 2; break; case 0x0C: // Gust speed (m/s) - gustLast = ConvertWindMSToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); + gustLast = ConvertUnits.WindMSToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); idx += 2; break; case 0x0D: //Rain Event (mm) if (cumulus.Gw1000PrimaryRainSensor == 0) { - StormRain = ConvertRainMMToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); + StormRain = ConvertUnits.RainMMToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); } idx += 2; break; case 0x0E: //Rain Rate (mm/h) if (cumulus.Gw1000PrimaryRainSensor == 0) { - rainRateLast = ConvertRainMMToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); + rainRateLast = ConvertUnits.RainMMToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); } idx += 2; break; @@ -933,7 +952,7 @@ private void GetLiveData() case 0x13: //Rain Year (mm) if (cumulus.Gw1000PrimaryRainSensor == 0) { - rainLast = ConvertRainMMToUser(GW1000Api.ConvertBigEndianUInt32(data, idx) / 10.0); + rainLast = ConvertUnits.RainMMToUser(GW1000Api.ConvertBigEndianUInt32(data, idx) / 10.0); } idx += 4; break; @@ -975,7 +994,7 @@ private void GetLiveData() { outdoortemp = tempInt16 / 10.0; } - DoExtraTemp(ConvertTempCToUser(tempInt16 / 10.0), chan); + DoExtraTemp(ConvertUnits.TempCToUser(tempInt16 / 10.0), chan); idx += 2; break; case 0x22: //Humidity 1, 0-100% @@ -1014,7 +1033,7 @@ private void GetLiveData() chan = data[idx - 1] - 0x2B + 2; // -> 2,4,6,8... chan /= 2; // -> 1,2,3,4... tempInt16 = GW1000Api.ConvertBigEndianInt16(data, idx); - DoSoilTemp(ConvertTempCToUser(tempInt16 / 10.0), chan); + DoSoilTemp(ConvertUnits.TempCToUser(tempInt16 / 10.0), chan); idx += 2; break; case 0x2C: //Soil Moisture1 (%) @@ -1081,7 +1100,7 @@ private void GetLiveData() break; case 0x60: //Lightning dist (1-40km) // Sends a default value of 255km until the first strike is detected - newLightningDistance = data[idx] == 0xFF ? 999 : ConvertKmtoUserUnits(data[idx]); + newLightningDistance = data[idx] == 0xFF ? 999 : ConvertUnits.KmtoUserUnits(data[idx]); idx += 1; break; case 0x61: //Lightning time (UTC) @@ -1126,11 +1145,11 @@ private void GetLiveData() tempInt16 = GW1000Api.ConvertBigEndianInt16(data, idx); if (cumulus.EcowittMapWN34[chan] == 0) // false = user temp, true = soil temp { - DoUserTemp(ConvertTempCToUser(tempInt16 / 10.0), chan); + DoUserTemp(ConvertUnits.TempCToUser(tempInt16 / 10.0), chan); } else { - DoSoilTemp(ConvertTempCToUser(tempInt16 / 10.0), cumulus.EcowittMapWN34[chan]); + DoSoilTemp(ConvertUnits.TempCToUser(tempInt16 / 10.0), cumulus.EcowittMapWN34[chan]); } // Firmware version 1.5.9 uses 2 data bytes, 1.6.0+ uses 3 data bytes if (fwVersion.CompareTo(new Version("1.6.0")) >= 0) @@ -1189,14 +1208,14 @@ private void GetLiveData() case 0x80: // Piezo Rain Rate if (cumulus.Gw1000PrimaryRainSensor == 1) { - rainRateLast = ConvertRainMMToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); + rainRateLast = ConvertUnits.RainMMToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); } idx += 2; break; case 0x81: // Piezo Rain Event if (cumulus.Gw1000PrimaryRainSensor == 1) { - StormRain = ConvertRainMMToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); + StormRain = ConvertUnits.RainMMToUser(GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0); } idx += 2; break; @@ -1215,7 +1234,7 @@ private void GetLiveData() case 0x86: // Piezo Yearly Rain if (cumulus.Gw1000PrimaryRainSensor == 1) { - rainLast = ConvertRainMMToUser(GW1000Api.ConvertBigEndianUInt32(data, idx) / 10.0); + rainLast = ConvertUnits.RainMMToUser(GW1000Api.ConvertBigEndianUInt32(data, idx) / 10.0); } idx += 4; break; @@ -1248,15 +1267,15 @@ private void GetLiveData() // Process outdoor temperature here, as GW1000 currently does not supply Dew Point so we have to calculate it in DoOutdoorTemp() if (outdoortemp > -999) - DoOutdoorTemp(ConvertTempCToUser(outdoortemp), dateTime); + DoOutdoorTemp(ConvertUnits.TempCToUser(outdoortemp), dateTime); // Same for extra T/H sensors for (var i = 1; i <= 8; i++) { if (ExtraHum[i] > 0) { - var dp = MeteoLib.DewPoint(ConvertUserTempToC(ExtraTemp[i]), ExtraHum[i]); - ExtraDewPoint[i] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(ExtraTemp[i]), ExtraHum[i]); + ExtraDewPoint[i] = ConvertUnits.TempCToUser(dp); } } @@ -1564,7 +1583,7 @@ private void GetPiezoRainData() #if DEBUG cumulus.LogDebugMessage($"GetPiezoRainData: Rain Year: {rain:f1} mm, Rate: {rRate:f1} mm/hr"); #endif - DoRain(ConvertRainMMToUser(rain.Value), ConvertRainMMToUser(rRate.Value), DateTime.Now); + DoRain(ConvertUnits.RainMMToUser(rain.Value), ConvertUnits.RainMMToUser(rRate.Value), DateTime.Now); } else { @@ -1588,7 +1607,7 @@ private bool DoCO2Decode(byte[] data, int index) try { - CO2_temperature = ConvertTempCToUser(GW1000Api.ConvertBigEndianInt16(data, idx) / 10.0); + CO2_temperature = ConvertUnits.TempCToUser(GW1000Api.ConvertBigEndianInt16(data, idx) / 10.0); idx += 2; CO2_humidity = data[idx++]; CO2_pm10 = GW1000Api.ConvertBigEndianUInt16(data, idx) / 10.0; diff --git a/CumulusMX/HttpStationAmbient.cs b/CumulusMX/HttpStationAmbient.cs index c97f8847..449f9f24 100644 --- a/CumulusMX/HttpStationAmbient.cs +++ b/CumulusMX/HttpStationAmbient.cs @@ -13,7 +13,7 @@ class HttpStationAmbient : WeatherStation private bool starting = true; private bool stopping = false; - public HttpStationAmbient(Cumulus cumulus, WeatherStation station = null) : base(cumulus) + public HttpStationAmbient(Cumulus cumulus, WeatherStation station = null) : base(cumulus, station != null) { this.station = station; @@ -144,9 +144,9 @@ public string ProcessData(IHttpContext context, bool main) } else { - var gustVal = ConvertWindMPHToUser(Convert.ToDouble(gust, CultureInfo.InvariantCulture)); + var gustVal = ConvertUnits.WindMPHToUser(Convert.ToDouble(gust, CultureInfo.InvariantCulture)); var dirVal = Convert.ToInt32(dir, CultureInfo.InvariantCulture); - var avgVal = ConvertWindMPHToUser(Convert.ToDouble(avg, CultureInfo.InvariantCulture)); + var avgVal = ConvertUnits.WindMPHToUser(Convert.ToDouble(avg, CultureInfo.InvariantCulture)); DoWind(gustVal, dirVal, avgVal, recDate); } } @@ -211,7 +211,7 @@ public string ProcessData(IHttpContext context, bool main) } else { - var pressVal = ConvertPressINHGToUser(Convert.ToDouble(press, CultureInfo.InvariantCulture)); + var pressVal = ConvertUnits.PressINHGToUser(Convert.ToDouble(press, CultureInfo.InvariantCulture)); DoPressure(pressVal, recDate); UpdatePressureTrendString(); } @@ -222,7 +222,7 @@ public string ProcessData(IHttpContext context, bool main) } else { - StationPressure = ConvertPressINHGToUser(Convert.ToDouble(stnPress, CultureInfo.InvariantCulture)); + StationPressure = ConvertUnits.PressINHGToUser(Convert.ToDouble(stnPress, CultureInfo.InvariantCulture)); } } catch (Exception ex) @@ -246,7 +246,7 @@ public string ProcessData(IHttpContext context, bool main) } else { - var tempVal = ConvertTempFToUser(Convert.ToDouble(temp, CultureInfo.InvariantCulture)); + var tempVal = ConvertUnits.TempFToUser(Convert.ToDouble(temp, CultureInfo.InvariantCulture)); DoIndoorTemp(tempVal); } } @@ -271,7 +271,7 @@ public string ProcessData(IHttpContext context, bool main) } else { - var tempVal = ConvertTempFToUser(Convert.ToDouble(temp, CultureInfo.InvariantCulture)); + var tempVal = ConvertUnits.TempFToUser(Convert.ToDouble(temp, CultureInfo.InvariantCulture)); DoOutdoorTemp(tempVal, recDate); } } @@ -304,8 +304,8 @@ public string ProcessData(IHttpContext context, bool main) } else { - var rainVal = ConvertRainINToUser(Convert.ToDouble(rain, CultureInfo.InvariantCulture)); - //var rateVal = ConvertRainINToUser(Convert.ToDouble(rRate, CultureInfo.InvariantCulture)); + var rainVal = ConvertUnits.RainINToUser(Convert.ToDouble(rain, CultureInfo.InvariantCulture)); + //var rateVal = ConvertUnits.RainINToUser(Convert.ToDouble(rRate, CultureInfo.InvariantCulture)); DoRain(rainVal, 0, recDate); } } @@ -333,10 +333,9 @@ public string ProcessData(IHttpContext context, bool main) } else { - var val = ConvertTempFToUser(Convert.ToDouble(dewpnt, CultureInfo.InvariantCulture)); + var val = ConvertUnits.TempFToUser(Convert.ToDouble(dewpnt, CultureInfo.InvariantCulture)); DoOutdoorDewpoint(val, recDate); } - } catch (Exception ex) { @@ -364,7 +363,7 @@ public string ProcessData(IHttpContext context, bool main) } else { - var val = ConvertTempFToUser(Convert.ToDouble(chill, CultureInfo.InvariantCulture)); + var val = ConvertUnits.TempFToUser(Convert.ToDouble(chill, CultureInfo.InvariantCulture)); DoWindChill(val, recDate); } } @@ -504,7 +503,6 @@ public string ProcessData(IHttpContext context, bool main) // pm10_in_24h - [float, µg/m^3] // pm_in_temp - [float, F] // pm_in_humidity - [int, %] - ProcessAirQuality(data, thisStation); } catch (Exception ex) @@ -541,7 +539,6 @@ public string ProcessData(IHttpContext context, bool main) // lightning_day - [int, count] // lightning_time - [int, Unix time] // lightning_distance - [float, km] - ProcessLightning(data, thisStation); } catch (Exception ex) @@ -630,7 +627,7 @@ private void ProcessExtraTemps(NameValueCollection data, WeatherStation station) { if (data["temp" + i + "f"] != null) { - station.DoExtraTemp(ConvertTempFToUser(Convert.ToDouble(data["temp" + i + "f"], CultureInfo.InvariantCulture)), i); + station.DoExtraTemp(ConvertUnits.TempFToUser(Convert.ToDouble(data["temp" + i + "f"], CultureInfo.InvariantCulture)), i); } } } @@ -668,7 +665,7 @@ private void ProcessSoilTemps(NameValueCollection data, WeatherStation station) { if (data["soiltemp" + i] != null) { - station.DoSoilTemp(ConvertTempFToUser(Convert.ToDouble(data["soiltemp" + i], CultureInfo.InvariantCulture)), i - 1); + station.DoSoilTemp(ConvertUnits.TempFToUser(Convert.ToDouble(data["soiltemp" + i], CultureInfo.InvariantCulture)), i - 1); } } } @@ -766,7 +763,7 @@ private void ProcessLightning(NameValueCollection data, WeatherStation station) var valDist = Convert.ToDouble(dist, CultureInfo.InvariantCulture); if (valDist != 255) { - LightningDistance = ConvertKmtoUserUnits(valDist); + LightningDistance = ConvertUnits.KmtoUserUnits(valDist); } var valTime = Convert.ToDouble(time, CultureInfo.InvariantCulture); @@ -844,11 +841,10 @@ private void ProcessExtraDewPoint(NameValueCollection data, WeatherStation stati { if (data["temp" + i + "f"] != null && data["humidity" + i] != null) { - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[i]), station.ExtraHum[i]); - station.ExtraDewPoint[i] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[i]), station.ExtraHum[i]); + station.ExtraDewPoint[i] = ConvertUnits.TempCToUser(dp); } } } - } } diff --git a/CumulusMX/HttpStationEcowitt.cs b/CumulusMX/HttpStationEcowitt.cs index 7ece95bd..8fc02c2e 100644 --- a/CumulusMX/HttpStationEcowitt.cs +++ b/CumulusMX/HttpStationEcowitt.cs @@ -24,7 +24,7 @@ class HttpStationEcowitt : WeatherStation private EcowittApi ecowittApi; private int maxArchiveRuns = 1; - public HttpStationEcowitt(Cumulus cumulus, WeatherStation station = null) : base(cumulus) + public HttpStationEcowitt(Cumulus cumulus, WeatherStation station = null) : base(cumulus, station != null) { this.station = station; @@ -221,11 +221,11 @@ private void GetHistoricData() public override string GetEcowittCameraUrl() { - if (cumulus.EcowittCameraMacAddress != null) + if ((cumulus.EcowittExtraUseCamera || station == null) && !string.IsNullOrEmpty(cumulus.EcowittCameraMacAddress)) { try { - EcowittCameraUrl = ecowittApi.GetCurrentCameraImageUrl(cumulus.cancellationToken, EcowittCameraUrl); + EcowittCameraUrl = ecowittApi.GetCurrentCameraImageUrl(EcowittCameraUrl, cumulus.cancellationToken); return EcowittCameraUrl; } catch (Exception ex) @@ -237,6 +237,24 @@ public override string GetEcowittCameraUrl() return null; } + public override string GetEcowittVideoUrl() + { + if ((cumulus.EcowittExtraUseCamera || station == null) && !string.IsNullOrEmpty(cumulus.EcowittCameraMacAddress)) + { + try + { + EcowittVideoUrl = ecowittApi.GetLastCameraVideoUrl(EcowittVideoUrl, cumulus.cancellationToken); + return EcowittVideoUrl; + } + catch (Exception ex) + { + cumulus.LogExceptionMessage(ex, "Error running Ecowitt Video URL"); + } + } + + return null; + } + public string ProcessData(IHttpContext context, bool main, DateTime? ts = null) { /* @@ -316,7 +334,6 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) if (recDate.Minute != lastMinute) { - // at start-up or every 20 minutes trigger output of uptime if ((recDate.Minute % 20) == 0 || lastMinute == -1 && data["runtime"] != null) { @@ -365,9 +382,9 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) } else { - var gustVal = ConvertWindMPHToUser(Convert.ToDouble(gust, invNum)); + var gustVal = ConvertUnits.WindMPHToUser(Convert.ToDouble(gust, invNum)); var dirVal = Convert.ToInt32(dir, invNum); - var spdVal = ConvertWindMPHToUser(Convert.ToDouble(spd, invNum)); + var spdVal = ConvertUnits.WindMPHToUser(Convert.ToDouble(spd, invNum)); DoWind(gustVal, dirVal, spdVal, recDate); @@ -439,7 +456,7 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) } else { - var pressVal = ConvertPressINHGToUser(Convert.ToDouble(press, invNum)); + var pressVal = ConvertUnits.PressINHGToUser(Convert.ToDouble(press, invNum)); DoPressure(pressVal, recDate); UpdatePressureTrendString(); } @@ -450,7 +467,7 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) } else { - StationPressure = ConvertPressINHGToUser(Convert.ToDouble(stnPress, invNum)); + StationPressure = ConvertUnits.PressINHGToUser(Convert.ToDouble(stnPress, invNum)); } } catch (Exception ex) @@ -470,7 +487,7 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) } else { - var tempVal = ConvertTempFToUser(Convert.ToDouble(data["tempinf"], invNum)); + var tempVal = ConvertUnits.TempFToUser(Convert.ToDouble(data["tempinf"], invNum)); DoIndoorTemp(tempVal); // user has mapped indoor humidity to outdoor @@ -500,7 +517,7 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) } else { - var tempVal = ConvertTempFToUser(Convert.ToDouble(data["tempf"], invNum)); + var tempVal = ConvertUnits.TempFToUser(Convert.ToDouble(data["tempf"], invNum)); DoOutdoorTemp(tempVal, recDate); haveTemp = true; } @@ -544,7 +561,7 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) rRate = data["rainratein"]; if (cumulus.StationOptions.UseRainForIsRaining == 2) { - IsRaining = Convert.ToDouble(data["​rrain_piezo"], invNum) > 0; + IsRaining = Convert.ToDouble(data["rrain_piezo"], invNum) > 0; cumulus.IsRainingAlarm.Triggered = IsRaining; } } @@ -572,8 +589,8 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) } else { - var rainVal = ConvertRainINToUser(Convert.ToDouble(rain, invNum)); - var rateVal = ConvertRainINToUser(Convert.ToDouble(rRate, invNum)); + var rainVal = ConvertUnits.RainINToUser(Convert.ToDouble(rain, invNum)); + var rateVal = ConvertUnits.RainINToUser(Convert.ToDouble(rRate, invNum)); DoRain(rainVal, rateVal, recDate); } } @@ -866,7 +883,7 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) } else { - var val = ConvertTempFToUser(Convert.ToDouble(data["dewptf"], invNum)); + var val = ConvertUnits.TempFToUser(Convert.ToDouble(data["dewptf"], invNum)); DoOutdoorDewpoint(val, recDate); } } @@ -903,7 +920,7 @@ public string ApplyData(string dataString, bool main, DateTime? ts = null) } else { - var val = ConvertTempFToUser(Convert.ToDouble(chill, invNum)); + var val = ConvertUnits.TempFToUser(Convert.ToDouble(chill, invNum)); DoWindChill(val, recDate); } } @@ -962,10 +979,10 @@ private bool ProcessExtraTemps(NameValueCollection data, WeatherStation station, { if (i == cumulus.Gw1000PrimaryTHSensor) { - station.DoOutdoorTemp(ConvertTempFToUser(Convert.ToDouble(data["temp" + i + "f"], invNum)), ts); + station.DoOutdoorTemp(ConvertUnits.TempFToUser(Convert.ToDouble(data["temp" + i + "f"], invNum)), ts); alreadyHaveTemp = true; } - station.DoExtraTemp(ConvertTempFToUser(Convert.ToDouble(data["temp" + i + "f"], invNum)), i); + station.DoExtraTemp(ConvertUnits.TempFToUser(Convert.ToDouble(data["temp" + i + "f"], invNum)), i); } else if (i == cumulus.Gw1000PrimaryTHSensor) { @@ -1017,14 +1034,14 @@ private void ProcessSoilTemps(NameValueCollection data, WeatherStation station) { if (data["soiltempf"] != null) { - station.DoSoilTemp(ConvertTempFToUser(Convert.ToDouble(data["soiltempf"], invNum)), 1); + station.DoSoilTemp(ConvertUnits.TempFToUser(Convert.ToDouble(data["soiltempf"], invNum)), 1); } for (var i = 2; i <= 16; i++) { if (data["soiltemp" + i + "f"] != null) { - station.DoSoilTemp(ConvertTempFToUser(Convert.ToDouble(data["soiltemp" + i + "f"], invNum)), i - 1); + station.DoSoilTemp(ConvertUnits.TempFToUser(Convert.ToDouble(data["soiltemp" + i + "f"], invNum)), i - 1); } } } @@ -1077,11 +1094,11 @@ private void ProcessUserTemp(NameValueCollection data, WeatherStation station) { if (cumulus.EcowittMapWN34[i] == 0) { - station.DoUserTemp(ConvertTempFToUser(Convert.ToDouble(data["tf_ch" + i], invNum)), i); + station.DoUserTemp(ConvertUnits.TempFToUser(Convert.ToDouble(data["tf_ch" + i], invNum)), i); } else { - station.DoSoilTemp(ConvertTempFToUser(Convert.ToDouble(data["tf_ch" + i], invNum)), cumulus.EcowittMapWN34[i]); + station.DoSoilTemp(ConvertUnits.TempFToUser(Convert.ToDouble(data["tf_ch" + i], invNum)), cumulus.EcowittMapWN34[i]); } } } @@ -1120,7 +1137,7 @@ private void ProcessCo2(NameValueCollection data, WeatherStation station) if (data["tf_co2"] != null) { - station.CO2_temperature = ConvertTempFToUser(Convert.ToDouble(data["tf_co2"], invNum)); + station.CO2_temperature = ConvertUnits.TempFToUser(Convert.ToDouble(data["tf_co2"], invNum)); } if (data["humi_co2"] != null) { @@ -1164,7 +1181,7 @@ private void ProcessLightning(NameValueCollection data, WeatherStation station) var valDist = Convert.ToDouble(dist, invNum); if (valDist != 255) { - station.LightningDistance = ConvertKmtoUserUnits(valDist); + station.LightningDistance = ConvertUnits.KmtoUserUnits(valDist); } var valTime = Convert.ToDouble(time, invNum); @@ -1212,18 +1229,18 @@ private void ProcessBatteries(NameValueCollection data) lowBatt = lowBatt || (data["wh90batt"] != null && Convert.ToDouble(data["wh90batt"], invNum) <= 2.4); for (var i = 1; i < 5; i++) { - lowBatt = lowBatt || (data["batt" + i] != null && data["batt" + i] == "1"); + lowBatt = lowBatt || (data["batt" + i] != null && data["batt" + i] == "1"); lowBatt = lowBatt || (data["soilbatt" + i] != null && Convert.ToDouble(data["soilbatt" + i], invNum) <= 1.2); lowBatt = lowBatt || (data["pm25batt" + i] != null && data["pm25batt" + i] == "1"); lowBatt = lowBatt || (data["leakbatt" + i] != null && data["leakbatt" + i] == "1"); - lowBatt = lowBatt || (data["tf_batt" + i] != null && Convert.ToDouble(data["tf_batt" + i], invNum) <= 1.2); + lowBatt = lowBatt || (data["tf_batt" + i] != null && Convert.ToDouble(data["tf_batt" + i], invNum) <= 1.2); lowBatt = lowBatt || (data["leaf_batt" + i] != null && Convert.ToDouble(data["leaf_batt" + i], invNum) <= 1.2); } for (var i = 5; i < 9; i++) { - lowBatt = lowBatt || (data["batt" + i] != null && data["batt" + i] == "1"); + lowBatt = lowBatt || (data["batt" + i] != null && data["batt" + i] == "1"); lowBatt = lowBatt || (data["soilbatt" + i] != null && Convert.ToDouble(data["soilbatt" + i], invNum) <= 1.2); - lowBatt = lowBatt || (data["tf_batt" + i] != null && Convert.ToDouble(data["tf_batt" + i], invNum) <= 1.2); + lowBatt = lowBatt || (data["tf_batt" + i] != null && Convert.ToDouble(data["tf_batt" + i], invNum) <= 1.2); lowBatt = lowBatt || (data["leaf_batt" + i] != null && Convert.ToDouble(data["leaf_batt" + i], invNum) <= 1.2); } @@ -1236,8 +1253,8 @@ private void ProcessExtraDewPoint(NameValueCollection data, WeatherStation stati { if (data["temp" + i + "f"] != null && data["humidity" + i] != null) { - var dp = MeteoLib.DewPoint(ConvertUserTempToC(station.ExtraTemp[i]), station.ExtraHum[i]); - station.ExtraDewPoint[i] = ConvertTempCToUser(dp); + var dp = MeteoLib.DewPoint(ConvertUnits.UserTempToC(station.ExtraTemp[i]), station.ExtraHum[i]); + station.ExtraDewPoint[i] = ConvertUnits.TempCToUser(dp); } } } diff --git a/CumulusMX/HttpStationWund.cs b/CumulusMX/HttpStationWund.cs index ce4e4f4a..80a30da7 100644 --- a/CumulusMX/HttpStationWund.cs +++ b/CumulusMX/HttpStationWund.cs @@ -103,9 +103,9 @@ GET Parameters - all fields are URL escaped } else { - var gustVal = ConvertWindMPHToUser(Convert.ToDouble(gust, CultureInfo.InvariantCulture)); + var gustVal = ConvertUnits.WindMPHToUser(Convert.ToDouble(gust, CultureInfo.InvariantCulture)); var dirVal = Convert.ToInt32(dir, CultureInfo.InvariantCulture); - var avgVal = ConvertWindMPHToUser(Convert.ToDouble(avg, CultureInfo.InvariantCulture)); + var avgVal = ConvertUnits.WindMPHToUser(Convert.ToDouble(avg, CultureInfo.InvariantCulture)); DoWind(gustVal, dirVal, avgVal, recDate); } } @@ -166,7 +166,7 @@ GET Parameters - all fields are URL escaped } else { - var pressVal = ConvertPressINHGToUser(Convert.ToDouble(press, CultureInfo.InvariantCulture)); + var pressVal = ConvertUnits.PressINHGToUser(Convert.ToDouble(press, CultureInfo.InvariantCulture)); DoPressure(pressVal, recDate); UpdatePressureTrendString(); } @@ -191,7 +191,7 @@ GET Parameters - all fields are URL escaped } else { - var tempVal = ConvertTempFToUser(Convert.ToDouble(temp, CultureInfo.InvariantCulture)); + var tempVal = ConvertUnits.TempFToUser(Convert.ToDouble(temp, CultureInfo.InvariantCulture)); DoIndoorTemp(tempVal); } } @@ -215,7 +215,7 @@ GET Parameters - all fields are URL escaped } else { - var tempVal = ConvertTempFToUser(Convert.ToDouble(temp, CultureInfo.InvariantCulture)); + var tempVal = ConvertUnits.TempFToUser(Convert.ToDouble(temp, CultureInfo.InvariantCulture)); DoOutdoorTemp(tempVal, recDate); } } @@ -241,7 +241,7 @@ GET Parameters - all fields are URL escaped } else { - var rainVal = ConvertRainINToUser(Convert.ToDouble(rain, CultureInfo.InvariantCulture)); + var rainVal = ConvertUnits.RainINToUser(Convert.ToDouble(rain, CultureInfo.InvariantCulture)); if (rainVal < previousRainCount) { @@ -279,7 +279,7 @@ GET Parameters - all fields are URL escaped } else { - var dpVal = ConvertTempFToUser(Convert.ToDouble(dewpnt, CultureInfo.InvariantCulture)); + var dpVal = ConvertUnits.TempFToUser(Convert.ToDouble(dewpnt, CultureInfo.InvariantCulture)); DoOutdoorDewpoint(dpVal, recDate); } } @@ -339,7 +339,7 @@ GET Parameters - all fields are URL escaped var str = data["temp" + i + "f"]; if (str != null && str != "-9999") { - DoExtraTemp(ConvertTempFToUser(Convert.ToDouble(str, CultureInfo.InvariantCulture)), i - 1); + DoExtraTemp(ConvertUnits.TempFToUser(Convert.ToDouble(str, CultureInfo.InvariantCulture)), i - 1); } } } @@ -392,7 +392,7 @@ GET Parameters - all fields are URL escaped var str1 = data["soiltempf"]; if (str1 != null && str1 != "-9999") { - DoSoilTemp(ConvertTempFToUser(Convert.ToDouble(str1, CultureInfo.InvariantCulture)), 1); + DoSoilTemp(ConvertUnits.TempFToUser(Convert.ToDouble(str1, CultureInfo.InvariantCulture)), 1); } for (var i = 2; i <= 4; i++) @@ -400,7 +400,7 @@ GET Parameters - all fields are URL escaped var str = data["soiltemp" + i + "f"]; if (str != null && str != "-9999") { - DoSoilTemp(ConvertTempFToUser(Convert.ToDouble(str, CultureInfo.InvariantCulture)), i); + DoSoilTemp(ConvertUnits.TempFToUser(Convert.ToDouble(str, CultureInfo.InvariantCulture)), i); } } } diff --git a/CumulusMX/ImetStation.cs b/CumulusMX/ImetStation.cs index 3af91adb..a12a1262 100644 --- a/CumulusMX/ImetStation.cs +++ b/CumulusMX/ImetStation.cs @@ -694,7 +694,7 @@ public override void getAndProcessHistoryData() if (sl[TEMP1AVGPOS].Length > 0) { - DoOutdoorTemp(ConvertTempCToUser(Convert.ToDouble(sl[TEMP1AVGPOS], provider)), timestamp); + DoOutdoorTemp(ConvertUnits.TempCToUser(Convert.ToDouble(sl[TEMP1AVGPOS], provider)), timestamp); // add in "archivePeriod" minutes worth of temperature to the temp samples tempsamplestoday += interval; @@ -738,9 +738,9 @@ public override void getAndProcessHistoryData() raindiff = raintotal - prevraintotal; } - double rainrate = ConvertRainMMToUser((raindiff) * (60.0 / cumulus.logints[cumulus.DataLogInterval])); + double rainrate = ConvertUnits.RainMMToUser((raindiff) * (60.0 / cumulus.logints[cumulus.DataLogInterval])); - DoRain(ConvertRainMMToUser(raintotal), rainrate, timestamp); + DoRain(ConvertUnits.RainMMToUser(raintotal), rainrate, timestamp); prevraintotal = raintotal; } @@ -748,17 +748,17 @@ public override void getAndProcessHistoryData() if ((sl[WINDAVGPOS].Length > 0) && (sl[TEMP1AVGPOS].Length > 0)) { // wind chill - double tempinC = ConvertUserTempToC(OutdoorTemperature); - double windinKPH = ConvertUserWindToKPH(WindAverage); + double tempinC = ConvertUnits.UserTempToC(OutdoorTemperature); + double windinKPH = ConvertUnits.UserWindToKPH(WindAverage); double value = MeteoLib.WindChill(tempinC, windinKPH); // value is now in Celsius, convert to units in use - value = ConvertTempCToUser(value); + value = ConvertUnits.TempCToUser(value); DoWindChill(value, timestamp); } if (sl[PRESSAVGPOS].Length > 0) { - DoPressure(ConvertPressMBToUser(Convert.ToDouble(sl[PRESSAVGPOS], provider)), timestamp); + DoPressure(ConvertUnits.PressMBToUser(Convert.ToDouble(sl[PRESSAVGPOS], provider)), timestamp); } // Cause wind chill calc @@ -781,13 +781,13 @@ public override void getAndProcessHistoryData() cumulus.DoCustomIntervalLogs(timestamp); AddRecentDataEntry(timestamp, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, - OutdoorHumidity, Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate, -1, -1); + OutdoorHumidity, Pressure, RainToday, SolarRad, UV, RainCounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate, -1, -1); DoTrendValues(timestamp); if (cumulus.StationOptions.CalculatedET && timestamp.Minute == 0) { // Start of a new hour, and we want to calculate ET in Cumulus - CalculateEvaoptranspiration(timestamp); + CalculateEvapotranspiration(timestamp); } UpdatePressureTrendString(); @@ -917,7 +917,7 @@ private void ImetGetData() !string.IsNullOrEmpty(sl[WINDPOS]) && double.TryParse(sl[WINDPOS], NumberStyles.Float, provider, out varDbl)) { windspeed = varDbl; - DoWind(ConvertWindMSToUser(windspeed), varInt, -1, now); + DoWind(ConvertUnits.WindMSToUser(windspeed), varInt, -1, now); } else { @@ -928,7 +928,7 @@ private void ImetGetData() if (!string.IsNullOrEmpty(sl[TEMP1POS]) && double.TryParse(sl[TEMP1POS], NumberStyles.Float, provider, out varDbl)) { temp1 = varDbl; - DoOutdoorTemp(ConvertTempCToUser(temp1), now); + DoOutdoorTemp(ConvertUnits.TempCToUser(temp1), now); if (windspeed > -99) { double windchill = MeteoLib.WindChill(temp1, windspeed * 3.6); @@ -947,12 +947,12 @@ private void ImetGetData() if (cumulus.StationOptions.LogExtraSensors) { // use second temp as Extra Temp 1 - DoExtraTemp(ConvertTempCToUser(varDbl), 1); + DoExtraTemp(ConvertUnits.TempCToUser(varDbl), 1); } else { // use second temp as wet bulb - DoWetBulb(ConvertTempCToUser(varDbl), now); + DoWetBulb(ConvertUnits.TempCToUser(varDbl), now); } } else @@ -973,7 +973,7 @@ private void ImetGetData() if (!string.IsNullOrEmpty(sl[PRESSPOS]) && double.TryParse(sl[PRESSPOS], NumberStyles.Float, provider, out varDbl)) { - DoPressure(ConvertPressMBToUser(varDbl), now); + DoPressure(ConvertUnits.PressMBToUser(varDbl), now); UpdatePressureTrendString(); } else @@ -984,7 +984,7 @@ private void ImetGetData() if (!string.IsNullOrEmpty(sl[RAINPOS]) && double.TryParse(sl[RAINPOS], NumberStyles.Float, provider, out varDbl)) { - DoRain(ConvertRainMMToUser(varDbl), -1, now); + DoRain(ConvertUnits.RainMMToUser(varDbl), -1, now); } else { diff --git a/CumulusMX/InternetSettings.cs b/CumulusMX/InternetSettings.cs index bc7cdf47..be48babe 100644 --- a/CumulusMX/InternetSettings.cs +++ b/CumulusMX/InternetSettings.cs @@ -70,6 +70,7 @@ public string UpdateConfig(IHttpContext context) Task.Run(() => cumulus.TestPhpUploadCompression()); } } + cumulus.FtpOptions.FtpMode = (Cumulus.FtpProtocols) settings.website.sslftp; cumulus.UTF8encode = settings.website.general.utf8encode; @@ -223,37 +224,6 @@ public string UpdateConfig(IHttpContext context) context.Response.StatusCode = 500; } - // MQTT - try - { - cumulus.MQTT.Server = settings.mqtt.server ?? string.Empty; - cumulus.MQTT.Port = settings.mqtt.port; - cumulus.MQTT.UseTLS = settings.mqtt.useTls; - cumulus.MQTT.Username = settings.mqtt.username ?? string.Empty; - cumulus.MQTT.Password = settings.mqtt.password ?? string.Empty; - cumulus.MQTT.EnableDataUpdate = settings.mqtt.dataUpdate.enabled; - if (cumulus.MQTT.EnableDataUpdate) - { - cumulus.MQTT.UpdateTemplate = settings.mqtt.dataUpdate.template ?? string.Empty; - } - cumulus.MQTT.EnableInterval = settings.mqtt.interval.enabled; - if (cumulus.MQTT.EnableInterval) - { - cumulus.MQTT.IntervalTime = settings.mqtt.interval.time; - cumulus.MQTT.IntervalTemplate = settings.mqtt.interval.template ?? string.Empty; - - cumulus.MQTTTimer.Interval = cumulus.MQTT.IntervalTime * 1000; - cumulus.MQTTTimer.Enabled = cumulus.MQTT.EnableInterval && !string.IsNullOrWhiteSpace(cumulus.MQTT.IntervalTemplate); - } - } - catch (Exception ex) - { - var msg = "Error processing MQTT settings: " + ex.Message; - cumulus.LogErrorMessage(msg); - errorMsg += msg + "\n\n"; - context.Response.StatusCode = 500; - } - // Moon Image try { @@ -354,21 +324,11 @@ public string UpdateConfig(IHttpContext context) { MqttPublisher.Setup(cumulus); } - if (cumulus.MQTT.EnableInterval) - { - cumulus.MQTTTimer.Elapsed -= cumulus.MQTTTimerTick; - cumulus.MQTTTimer.Elapsed += cumulus.MQTTTimerTick; - cumulus.MQTTTimer.Start(); - } else { - cumulus.MQTTTimer.Stop(); + MqttPublisher.ReadTemplateFiles(); } } - else - { - cumulus.MQTTTimer.Stop(); - } } catch (Exception ex) { @@ -519,30 +479,6 @@ public string GetAlpacaFormData() realtimeprogramparams = cumulus.RealtimeParams }; - var mqttUpdate = new JsonInternetSettingsMqttDataupdate() - { - enabled = cumulus.MQTT.EnableDataUpdate, - template = cumulus.MQTT.UpdateTemplate - }; - - var mqttInterval = new JsonInternetSettingsMqttInterval() - { - enabled = cumulus.MQTT.EnableInterval, - time = cumulus.MQTT.IntervalTime, - template = cumulus.MQTT.IntervalTemplate - }; - - var mqttsettings = new JsonInternetSettingsMqtt() - { - server = cumulus.MQTT.Server, - port = cumulus.MQTT.Port, - useTls = cumulus.MQTT.UseTLS, - username = cumulus.MQTT.Username, - password = cumulus.MQTT.Password, - dataUpdate = mqttUpdate, - interval = mqttInterval - }; - var moonimagesettings = new JsonInternetSettingsMoonImage() { enabled = cumulus.MoonImage.Enabled, @@ -587,7 +523,6 @@ public string GetAlpacaFormData() website = websitesettings, websettings = websettings, externalprograms = externalprograms, - mqtt = mqttsettings, moonimage = moonimagesettings, proxies = proxy, emailsettings = email, @@ -601,6 +536,7 @@ public string GetExtraWebFilesData() { var json = new StringBuilder(10240); 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\":\"Upload\",\"datatype\":\"boolean\",\"editable\":true},{\"name\":\"utf8\",\"label\":\"UTF8\",\"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++) { var local = cumulus.ExtraFiles[i].local.Replace("\\", "\\\\").Replace("/", "\\/"); @@ -697,7 +633,6 @@ public class JsonInternetSettingsData public JsonInternetSettingsWebsite website { get; set; } public JsonInternetSettingsWebSettings websettings { get; set; } public JsonInternetSettingsExternalPrograms externalprograms { get; set; } - public JsonInternetSettingsMqtt mqtt { get; set; } public JsonInternetSettingsMoonImage moonimage { get; set; } public JsonInternetSettingsProxySettings proxies { get; set; } public JsonEmailSettings emailsettings { get; set; } @@ -773,7 +708,6 @@ public class JsonInternetSettingsWebSettingsIntervalFiles { public JsonInternetSettingsFileSettings[] files { get; set; } public string wxnowcomment { get; set; } - } public class JsonInternetSettingsWebSettingsRealtime @@ -795,32 +729,6 @@ public class JsonInternetSettingsExternalPrograms public string dailyprogramparams { get; set; } } - public class JsonInternetSettingsMqtt - { - public string server { get; set; } - public int port { get; set; } - public bool useTls { get; set; } - public string username { get; set; } - public string password { get; set; } - public JsonInternetSettingsMqttDataupdate dataUpdate { get; set; } - public JsonInternetSettingsMqttInterval interval { get; set; } - } - - public class JsonInternetSettingsMqttDataupdate - { - public bool enabled { get; set; } - public string template { get; set; } - } - - public class JsonInternetSettingsMqttInterval - { - public bool enabled { get; set; } - public int time { get; set; } - public string topic { get; set; } - public string template { get; set; } - public bool retained { get; set; } - } - public class JsonInternetSettingsMoonImage { public bool enabled { get; set; } @@ -831,7 +739,6 @@ public class JsonInternetSettingsMoonImage public string copydest { get; set; } } - public class JsonInternetSettingsProxySettings { public JsonInternetSettingsHTTPproxySettings httpproxy { get; set; } diff --git a/CumulusMX/LangSettings.cs b/CumulusMX/LangSettings.cs index b5bf7845..6ef3c10a 100644 --- a/CumulusMX/LangSettings.cs +++ b/CumulusMX/LangSettings.cs @@ -103,10 +103,33 @@ public string GetAlpacaFormData() Pm10_24hr = cumulus.Trans.CO2_pm10_24hrCaption }; - var alarms = new AlarmEmails() + var alarmNames = new AlarmStrings() + { + windGustAbove = cumulus.HighGustAlarm.Name, + pressureAbove = cumulus.HighPressAlarm.Name, + tempAbove = cumulus.HighTempAlarm.Name, + pressBelow = cumulus.LowPressAlarm.Name, + tempBelow = cumulus.LowTempAlarm.Name, + pressDown = cumulus.PressChangeAlarm.NameDown, + pressUp = cumulus.PressChangeAlarm.NameUp, + rainAbove = cumulus.HighRainTodayAlarm.Name, + rainRateAbove = cumulus.HighRainRateAlarm.Name, + sensorLost = cumulus.SensorAlarm.Name, + tempDown = cumulus.TempChangeAlarm.NameDown, + tempUp = cumulus.TempChangeAlarm.NameUp, + windAbove = cumulus.HighWindAlarm.Name, + dataStopped = cumulus.DataStoppedAlarm.Name, + batteryLow = cumulus.BatteryLowAlarm.Name, + dataSpike = cumulus.SpikeAlarm.Name, + upgrade = cumulus.UpgradeAlarm.Name, + httpStopped = cumulus.ThirdPartyAlarm.Name, + mySqlStopped = cumulus.MySqlUploadAlarm.Name, + newRecord = cumulus.NewRecordAlarm.Name, + ftpStopped = cumulus.FtpAlarm.Name + }; + + var alarmEmail = new AlarmStrings() { - subject = cumulus.Trans.AlarmEmailSubject, - preamble = cumulus.Trans.AlarmEmailPreamble, windGustAbove = cumulus.HighGustAlarm.EmailMsg, pressureAbove = cumulus.HighPressAlarm.EmailMsg, tempAbove = cumulus.HighTempAlarm.EmailMsg, @@ -130,6 +153,14 @@ public string GetAlpacaFormData() ftpStopped = cumulus.FtpAlarm.EmailMsg }; + var alarmSettings = new AlarmSettings() + { + subject = cumulus.Trans.AlarmEmailSubject, + preamble = cumulus.Trans.AlarmEmailPreamble, + names = alarmNames, + email = alarmEmail + }; + var settings = new Settings() { accessible = cumulus.ProgramOptions.EnableAccessibility, @@ -149,7 +180,7 @@ public string GetAlpacaFormData() solar = solar, davisForecast = davisForecast, co2 = co2, - alarms = alarms + alarms = alarmSettings }; @@ -356,27 +387,50 @@ public string UpdateConfig(IHttpContext context) { cumulus.Trans.AlarmEmailSubject = settings.alarms.subject.Trim(); cumulus.Trans.AlarmEmailPreamble = settings.alarms.preamble.Trim(); - cumulus.HighGustAlarm.EmailMsg = settings.alarms.windGustAbove.Trim(); - cumulus.HighPressAlarm.EmailMsg = settings.alarms.pressureAbove.Trim(); - cumulus.HighTempAlarm.EmailMsg = settings.alarms.tempAbove.Trim(); - cumulus.LowPressAlarm.EmailMsg = settings.alarms.pressBelow.Trim(); - cumulus.LowTempAlarm.EmailMsg = settings.alarms.tempBelow.Trim(); - cumulus.PressChangeAlarm.EmailMsgDn = settings.alarms.pressDown.Trim(); - cumulus.PressChangeAlarm.EmailMsgUp = settings.alarms.pressUp.Trim(); - cumulus.HighRainTodayAlarm.EmailMsg = settings.alarms.rainAbove.Trim(); - cumulus.HighRainRateAlarm.EmailMsg = settings.alarms.rainRateAbove.Trim(); - cumulus.SensorAlarm.EmailMsg = settings.alarms.sensorLost.Trim(); - cumulus.TempChangeAlarm.EmailMsgDn = settings.alarms.tempDown.Trim(); - cumulus.TempChangeAlarm.EmailMsgUp = settings.alarms.tempUp.Trim(); - cumulus.HighWindAlarm.EmailMsg = settings.alarms.windAbove.Trim(); - cumulus.DataStoppedAlarm.EmailMsg = settings.alarms.dataStopped.Trim(); - cumulus.BatteryLowAlarm.EmailMsg = settings.alarms.batteryLow.Trim(); - cumulus.SpikeAlarm.EmailMsg = settings.alarms.dataSpike.Trim(); - cumulus.UpgradeAlarm.EmailMsg = settings.alarms.upgrade.Trim(); - cumulus.ThirdPartyAlarm.EmailMsg = settings.alarms.httpStopped.Trim(); - cumulus.MySqlUploadAlarm.EmailMsg = settings.alarms.mySqlStopped.Trim(); - cumulus.NewRecordAlarm.EmailMsg = settings.alarms.newRecord.Trim(); - cumulus.FtpAlarm.EmailMsg = settings.alarms.ftpStopped.Trim(); + // Names + cumulus.HighGustAlarm.Name = settings.alarms.names.windGustAbove.Trim(); + cumulus.HighPressAlarm.Name = settings.alarms.names.pressureAbove.Trim(); + cumulus.HighTempAlarm.Name = settings.alarms.names.tempAbove.Trim(); + cumulus.LowPressAlarm.Name = settings.alarms.names.pressBelow.Trim(); + cumulus.LowTempAlarm.Name = settings.alarms.names.tempBelow.Trim(); + cumulus.PressChangeAlarm.NameDown = settings.alarms.names.pressDown.Trim(); + cumulus.PressChangeAlarm.NameUp = settings.alarms.names.pressUp.Trim(); + cumulus.HighRainTodayAlarm.Name = settings.alarms.names.rainAbove.Trim(); + cumulus.HighRainRateAlarm.Name = settings.alarms.names.rainRateAbove.Trim(); + cumulus.SensorAlarm.Name = settings.alarms.names.sensorLost.Trim(); + cumulus.TempChangeAlarm.NameDown = settings.alarms.names.tempDown.Trim(); + cumulus.TempChangeAlarm.NameUp = settings.alarms.names.tempUp.Trim(); + cumulus.HighWindAlarm.Name = settings.alarms.names.windAbove.Trim(); + cumulus.DataStoppedAlarm.Name = settings.alarms.names.dataStopped.Trim(); + cumulus.BatteryLowAlarm.Name = settings.alarms.names.batteryLow.Trim(); + cumulus.SpikeAlarm.Name = settings.alarms.names.dataSpike.Trim(); + cumulus.UpgradeAlarm.Name = settings.alarms.names.upgrade.Trim(); + cumulus.ThirdPartyAlarm.Name = settings.alarms.names.httpStopped.Trim(); + cumulus.MySqlUploadAlarm.Name = settings.alarms.names.mySqlStopped.Trim(); + cumulus.NewRecordAlarm.Name = settings.alarms.names.newRecord.Trim(); + cumulus.FtpAlarm.Name = settings.alarms.names.ftpStopped.Trim(); + // Email + cumulus.HighGustAlarm.EmailMsg = settings.alarms.email.windGustAbove.Trim(); + cumulus.HighPressAlarm.EmailMsg = settings.alarms.email.pressureAbove.Trim(); + cumulus.HighTempAlarm.EmailMsg = settings.alarms.email.tempAbove.Trim(); + cumulus.LowPressAlarm.EmailMsg = settings.alarms.email.pressBelow.Trim(); + cumulus.LowTempAlarm.EmailMsg = settings.alarms.email.tempBelow.Trim(); + cumulus.PressChangeAlarm.EmailMsgDn = settings.alarms.email.pressDown.Trim(); + cumulus.PressChangeAlarm.EmailMsgUp = settings.alarms.email.pressUp.Trim(); + cumulus.HighRainTodayAlarm.EmailMsg = settings.alarms.email.rainAbove.Trim(); + cumulus.HighRainRateAlarm.EmailMsg = settings.alarms.email.rainRateAbove.Trim(); + cumulus.SensorAlarm.EmailMsg = settings.alarms.email.sensorLost.Trim(); + cumulus.TempChangeAlarm.EmailMsgDn = settings.alarms.email.tempDown.Trim(); + cumulus.TempChangeAlarm.EmailMsgUp = settings.alarms.email.tempUp.Trim(); + cumulus.HighWindAlarm.EmailMsg = settings.alarms.email.windAbove.Trim(); + cumulus.DataStoppedAlarm.EmailMsg = settings.alarms.email.dataStopped.Trim(); + cumulus.BatteryLowAlarm.EmailMsg = settings.alarms.email.batteryLow.Trim(); + cumulus.SpikeAlarm.EmailMsg = settings.alarms.email.dataSpike.Trim(); + cumulus.UpgradeAlarm.EmailMsg = settings.alarms.email.upgrade.Trim(); + cumulus.ThirdPartyAlarm.EmailMsg = settings.alarms.email.httpStopped.Trim(); + cumulus.MySqlUploadAlarm.EmailMsg = settings.alarms.email.mySqlStopped.Trim(); + cumulus.NewRecordAlarm.EmailMsg = settings.alarms.email.newRecord.Trim(); + cumulus.FtpAlarm.EmailMsg = settings.alarms.email.ftpStopped.Trim(); } catch (Exception ex) { @@ -481,10 +535,16 @@ private class Co2Captions public string Pm10_24hr { get; set; } } - private class AlarmEmails + private class AlarmSettings { public string subject { get; set; } public string preamble { get; set; } + public AlarmStrings names { get; set; } + public AlarmStrings email { get; set; } + } + + private class AlarmStrings + { public string windGustAbove { get; set; } public string pressureAbove { get; set; } public string tempAbove { get; set; } @@ -527,7 +587,7 @@ private class Settings public Solar solar { get; set; } public DavisForecast davisForecast { get; set; } public Co2Captions co2 { get; set; } - public AlarmEmails alarms { get; set; } + public AlarmSettings alarms { get; set; } } } } diff --git a/CumulusMX/Libs/sqlite3-x64.dll b/CumulusMX/Libs/sqlite3-x64.dll index e4f4e9ad..5bb4c849 100644 Binary files a/CumulusMX/Libs/sqlite3-x64.dll and b/CumulusMX/Libs/sqlite3-x64.dll differ diff --git a/CumulusMX/Libs/sqlite3-x86.dll b/CumulusMX/Libs/sqlite3-x86.dll index c72be246..62e4e866 100644 Binary files a/CumulusMX/Libs/sqlite3-x86.dll and b/CumulusMX/Libs/sqlite3-x86.dll differ diff --git a/CumulusMX/MeteoLib.cs b/CumulusMX/MeteoLib.cs index 61777ae9..05436e30 100644 --- a/CumulusMX/MeteoLib.cs +++ b/CumulusMX/MeteoLib.cs @@ -476,12 +476,12 @@ public static double CalulateEvapotranspiration(DateTime ts) // Mean temperature in Fahrenheit var result = RecentDataDb.Query("select avg(OutsideTemp) temp, avg(WindSpeed) wind, avg(SolarRad) solar, avg(Humidity) hum from RecentData where Timestamp >= ?", onehourago); - var meanTempC = ConvertUserTempToC(result[0].temp); + var meanTempC = ConvertUnits.UserTempToC(result[0].temp); var meanTempK = meanTempC + 273.16; - var meanWind = ConvertUserWindToMS(result[0].wind); + var meanWind = ConvertUnits.UserWindToMS(result[0].wind); var meanHum = result[0].hum; var meanSolar = result[0].solar; - var pressure = ConvertUserPressToMB(AltimeterPressure) / 100; // need kPa + var pressure = ConvertUnits.UserPressToMB(AltimeterPressure) / 100; // need kPa var satVapPress = SaturationVapourPressure2008(meanTempC); var waterVapour = satVapPress * meanHum / 100; diff --git a/CumulusMX/MqttPublisher.cs b/CumulusMX/MqttPublisher.cs index 7832e93d..42f72639 100644 --- a/CumulusMX/MqttPublisher.cs +++ b/CumulusMX/MqttPublisher.cs @@ -8,6 +8,7 @@ using MQTTnet.Client; using ServiceStack; +using ServiceStack.Text; namespace CumulusMX { @@ -16,7 +17,9 @@ public static class MqttPublisher private static Cumulus cumulus; private static MqttClient mqttClient; public static bool configured; - private static Dictionary publishedTopics; + private static readonly Dictionary publishedTopics = new Dictionary(); + private static MqttTemplate updateTemplate; + private static MqttTemplate intervalTemplate; public static void Setup(Cumulus cumulus) { @@ -63,7 +66,7 @@ public static void Setup(Cumulus cumulus) mqttClient.DisconnectedAsync += (async e => { cumulus.LogWarningMessage("Error: MQTT disconnected from the server"); - await Task.Delay(TimeSpan.FromSeconds(5)); + await Task.Delay(TimeSpan.FromSeconds(30)); cumulus.LogDebugMessage("MQTT attempting to reconnect with server"); try @@ -77,12 +80,65 @@ public static void Setup(Cumulus cumulus) } }); - publishedTopics = new Dictionary(); + ReadTemplateFiles(); configured = true; } + public static void ReadTemplateFiles() + { + try + { + updateTemplate = null; + + if (cumulus.MQTT.EnableDataUpdate && !string.IsNullOrEmpty(cumulus.MQTT.UpdateTemplate)) + { + // read the config file into memory + var template = "mqtt/" + cumulus.MQTT.UpdateTemplate; + + if (File.Exists(template)) + { + // use template file + cumulus.LogMessage($"MQTT: Reading template file - {template}"); + + // read the file + var templateText = File.ReadAllText(template); + updateTemplate = templateText.FromJson(); + } + } + } + catch (Exception ex) + { + cumulus.LogErrorMessage($"MQTT: Error reading update template file {cumulus.MQTT.UpdateTemplate}. Message: {ex.Message}"); + } + + try + { + intervalTemplate = null; + + if (cumulus.MQTT.EnableInterval && !string.IsNullOrEmpty(cumulus.MQTT.IntervalTemplate)) + { + // read the config file into memory + var template = "mqtt/" + cumulus.MQTT.IntervalTemplate; + + if (File.Exists(template)) + { + // use template file + cumulus.LogMessage($"MQTT: Reading template file - {template}"); + + // read the file + var templateText = File.ReadAllText(template); + intervalTemplate = templateText.FromJson(); + } + } + } + catch (Exception ex) + { + cumulus.LogErrorMessage($"MQTT: Error reading interval template file {cumulus.MQTT.IntervalTemplate}. Message: {ex.Message}"); + } + } + private static async Task SendMessageAsync(string topic, string message, bool retain) { cumulus.LogDataMessage($"MQTT: publishing to topic '{topic}', message '{message}'"); @@ -116,68 +172,74 @@ private static async void Connect(MQTTnet.Client.MqttClientOptions options) } - public static void UpdateMQTTfeed(string feedType) + public static void UpdateMQTTfeed(string feedType, DateTime? now) { - var template = "mqtt/"; + MqttTemplate mqttTemplate; if (feedType == "Interval") { - template += cumulus.MQTT.IntervalTemplate; + if (intervalTemplate == null) + return; + + mqttTemplate = intervalTemplate; } else { - template += cumulus.MQTT.UpdateTemplate; - } + if (updateTemplate == null) + return; - if (!File.Exists(template)) - return; - - // use template file - cumulus.LogDebugMessage($"MQTT: Using template - {template}"); + mqttTemplate = updateTemplate; + } - // read the file - var templateText = File.ReadAllText(template); - var templateObj = templateText.FromJson(); // process each of the topics in turn try { - foreach (var feed in templateObj.topics) + foreach (var topic in mqttTemplate.topics) { + if (feedType == "Interval" && now.Value.ToUnixTime() % (topic.interval ?? 600) != 0) + { + // this topic is not ready to update + //cumulus.LogDebugMessage($"MQTT: Topic {topic.topic} not ready yet"); + continue; + } + + cumulus.LogDebugMessage($"MQTT: Processing {feedType} Topic: {topic.topic}"); + bool useAltResult = false; var mqttTokenParser = new TokenParser(cumulus.TokenParserOnToken) { Encoding = new System.Text.UTF8Encoding(false) }; - if ((feedType == "DataUpdate") && (feed.doNotTriggerOnTags != null)) + if ((feedType == "DataUpdate") && (topic.doNotTriggerOnTags != null)) { useAltResult = true; - mqttTokenParser.AltResultNoParseList = feed.doNotTriggerOnTags; + mqttTokenParser.AltResultNoParseList = topic.doNotTriggerOnTags; } - mqttTokenParser.InputText = feed.data; + mqttTokenParser.InputText = topic.data; string message = mqttTokenParser.ToStringFromString(); if (useAltResult) { - if (!(publishedTopics.ContainsKey(feed.data) && (publishedTopics[feed.data] == mqttTokenParser.AltResult))) + if (!(publishedTopics.ContainsKey(topic.data) && (publishedTopics[topic.data] == mqttTokenParser.AltResult))) { // send the message - _ = SendMessageAsync(feed.topic, message, feed.retain); + _ = SendMessageAsync(topic.topic, message, topic.retain); - if (publishedTopics.ContainsKey(feed.data)) - publishedTopics[feed.data] = mqttTokenParser.AltResult; + if (publishedTopics.ContainsKey(topic.data)) + publishedTopics[topic.data] = mqttTokenParser.AltResult; else - publishedTopics.Add(feed.data, mqttTokenParser.AltResult); + publishedTopics.Add(topic.data, mqttTokenParser.AltResult); } } else { - _ = SendMessageAsync(feed.topic, message, feed.retain); + _ = SendMessageAsync(topic.topic, message, topic.retain); } } } catch (Exception ex) { - cumulus.LogErrorMessage($"UpdateMQTTfeed: Error processing the template file [{template}], error = {ex.Message}"); + cumulus.LogErrorMessage($"UpdateMQTTfeed: Error processing the template file for [{feedType}], error = {ex.Message}"); } } } diff --git a/CumulusMX/MqttSettings.cs b/CumulusMX/MqttSettings.cs new file mode 100644 index 00000000..054e18b4 --- /dev/null +++ b/CumulusMX/MqttSettings.cs @@ -0,0 +1,157 @@ +using System; +using System.IO; +using System.Net; + +using EmbedIO; + +using ServiceStack; + + +namespace CumulusMX +{ + public class MqttSettings + { + private readonly Cumulus cumulus; + + public MqttSettings(Cumulus cumulus) + { + this.cumulus = cumulus; + } + + public string UpdateConfig(IHttpContext context) + { + var errorMsg = ""; + var json = ""; + MqttConfig settings; + + context.Response.StatusCode = 200; + + try + { + var data = new StreamReader(context.Request.InputStream).ReadToEnd(); + + // Start at char 5 to skip the "json:" prefix + json = WebUtility.UrlDecode(data.Substring(5)); + + // de-serialize it to the settings structure + settings = json.FromJson(); + } + catch (Exception ex) + { + var msg = "Error de-serializing MQTT Settings JSON: " + ex.Message; + cumulus.LogErrorMessage(msg); + cumulus.LogDebugMessage("MQTT Data: " + json); + context.Response.StatusCode = 500; + return msg; + } + + + // process the settings + try + { + cumulus.LogMessage("Updating internet settings"); + + // MQTT + try + { + cumulus.MQTT.Server = settings.server ?? string.Empty; + cumulus.MQTT.Port = settings.port; + cumulus.MQTT.UseTLS = settings.useTls; + cumulus.MQTT.Username = settings.username ?? string.Empty; + cumulus.MQTT.Password = settings.password ?? string.Empty; + cumulus.MQTT.EnableDataUpdate = settings.dataUpdate.enabled; + if (cumulus.MQTT.EnableDataUpdate) + { + cumulus.MQTT.UpdateTemplate = settings.dataUpdate.template ?? string.Empty; + } + + cumulus.MQTT.EnableInterval = settings.interval.enabled; + if (cumulus.MQTT.EnableInterval) + { + cumulus.MQTT.IntervalTemplate = settings.interval.template ?? string.Empty; + } + } + catch (Exception ex) + { + var msg = "Error processing MQTT settings: " + ex.Message; + cumulus.LogErrorMessage(msg); + errorMsg += msg + "\n\n"; + context.Response.StatusCode = 500; + } + + // Save the settings + cumulus.WriteIniFile(); + + // Setup MQTT + if (cumulus.MQTT.EnableDataUpdate || cumulus.MQTT.EnableInterval) + { + if (!MqttPublisher.configured) + { + MqttPublisher.Setup(cumulus); + } + else + { + MqttPublisher.ReadTemplateFiles(); + } + } + } + catch (Exception ex) + { + var msg = "Error processing MQTT settings: " + ex.Message; + cumulus.LogErrorMessage(msg); + cumulus.LogDebugMessage("MQTT data: " + json); + errorMsg += msg; + context.Response.StatusCode = 500; + } + + return context.Response.StatusCode == 200 ? "success" : errorMsg; + } + + public string GetAlpacaFormData() + { + // Build the settings data, convert to JSON, and return it + + var mqttUpdate = new MqttData() + { + enabled = cumulus.MQTT.EnableDataUpdate, + template = cumulus.MQTT.UpdateTemplate + }; + + var mqttInterval = new MqttData() + { + enabled = cumulus.MQTT.EnableInterval, + template = cumulus.MQTT.IntervalTemplate + }; + + var mqttsettings = new MqttConfig() + { + server = cumulus.MQTT.Server, + port = cumulus.MQTT.Port, + useTls = cumulus.MQTT.UseTLS, + username = cumulus.MQTT.Username, + password = cumulus.MQTT.Password, + dataUpdate = mqttUpdate, + interval = mqttInterval + }; + + return mqttsettings.ToJson(); + } + + private class MqttConfig + { + public string server { get; set; } + public int port { get; set; } + public bool useTls { get; set; } + public string username { get; set; } + public string password { get; set; } + public MqttData dataUpdate { get; set; } + public MqttData interval { get; set; } + } + + private class MqttData + { + public bool enabled { get; set; } + public string template { get; set; } + } + } +} diff --git a/CumulusMX/MysqlSettings.cs b/CumulusMX/MysqlSettings.cs index 632be2eb..dfd0a5a2 100644 --- a/CumulusMX/MysqlSettings.cs +++ b/CumulusMX/MysqlSettings.cs @@ -63,7 +63,6 @@ public string GetAlpacaFormData() { enabled = cumulus.MySqlSettings.CustomSecs.Enabled, interval = cumulus.MySqlSettings.CustomSecs.Interval - }; var cmdCnt = 1; diff --git a/CumulusMX/NOAA.cs b/CumulusMX/NOAA.cs index e7f17da3..97d02926 100644 --- a/CumulusMX/NOAA.cs +++ b/CumulusMX/NOAA.cs @@ -273,8 +273,9 @@ public string CreateMonthlyReport(DateTime thedate) if (dayList[daynumber].valid) { // already had this date - error! - cumulus.LogWarningMessage($"Duplicate entry in dayfile: {day.Date}."); - continue; + cumulus.LogErrorMessage($"Duplicate entry in dayfile: {day.Date:d}."); + cumulus.LogMessage("Please edit the file to correct the error"); + return $"Error, duplicate entry in dayfile for {day.Date:d}"; } // max temp @@ -343,16 +344,16 @@ public string CreateMonthlyReport(DateTime thedate) // mean = (high + low) / 2 // mean > 65F = cooling = high - 65 // mean < 65F = heating = 65 - low - if (station.ConvertUserTempToF(meantemp) > 65) + if (ConvertUnits.UserTempToF(meantemp) > 65) { dayList[daynumber].heatingdegdays = 0; - dayList[daynumber].coolingdegdays = dayList[daynumber].maxtemp - station.ConvertTempFToUser(65); + dayList[daynumber].coolingdegdays = dayList[daynumber].maxtemp - ConvertUnits.TempFToUser(65); totalcooling += dayList[daynumber].coolingdegdays; } else { dayList[daynumber].coolingdegdays = 0; - dayList[daynumber].heatingdegdays = station.ConvertTempFToUser(65) - dayList[daynumber].mintemp; + dayList[daynumber].heatingdegdays = ConvertUnits.TempFToUser(65) - dayList[daynumber].mintemp; totalheating += dayList[daynumber].heatingdegdays; } @@ -820,9 +821,20 @@ public string CreateYearlyReport(DateTime thedate) if (thisMonth.Count == 0) continue; + var lastDay = DateTime.MinValue; foreach (var day in thisMonth) { + if (day.Date == lastDay) + { + // already had this date - error! + cumulus.LogWarningMessage($"Duplicate entry in dayfile: {day.Date:d}."); + cumulus.LogMessage("Please edit the file to correct the error"); + return $"Error, duplicate entry in dayfile for {day.Date:d}"; + } + + lastDay = day.Date; + MonthList[month].totalmaxtemp += day.HighTemp; MonthList[month].totalmintemp += day.LowTemp; @@ -868,15 +880,15 @@ public string CreateYearlyReport(DateTime thedate) // mean = (high + low) / 2 // mean > 65F = cooling = high - 65 // mean < 65F = heating = 65 - low - if (station.ConvertUserTempToF(meantemp) > 65) + if (ConvertUnits.UserTempToF(meantemp) > 65) { - var cool = day.HighTemp - station.ConvertTempFToUser(65); + var cool = day.HighTemp - ConvertUnits.TempFToUser(65); MonthList[month].coolingdegdays += cool; totalcooling += cool; } else { - var heat = station.ConvertTempFToUser(65) - day.LowTemp; + var heat = ConvertUnits.TempFToUser(65) - day.LowTemp; MonthList[month].heatingdegdays += heat; totalheating += heat; } diff --git a/CumulusMX/Program.cs b/CumulusMX/Program.cs index 3e45c57b..fb169ff2 100644 --- a/CumulusMX/Program.cs +++ b/CumulusMX/Program.cs @@ -283,7 +283,8 @@ private static void RunAsAConsole(int port, bool debug) _ = new ExitHandler(); } - cumulus = new Cumulus(port, debug, ""); + cumulus = new Cumulus(); + cumulus.Initialise(port, debug, ""); if (!exitSystem) { diff --git a/CumulusMX/Properties/launchSettings.json b/CumulusMX/Properties/launchSettings.json index 91e544c8..a4394f1e 100644 --- a/CumulusMX/Properties/launchSettings.json +++ b/CumulusMX/Properties/launchSettings.json @@ -1,7 +1,8 @@ { "profiles": { "CumulusMX": { - "commandName": "Project" + "commandName": "Project", + "commandLineArgs": "-lang en_GB" } } } \ No newline at end of file diff --git a/CumulusMX/Simulator.cs b/CumulusMX/Simulator.cs index c05de664..34491738 100644 --- a/CumulusMX/Simulator.cs +++ b/CumulusMX/Simulator.cs @@ -98,21 +98,21 @@ public override void Stop() private void applyData(DateTime recDate) { - cumulus.LogDataMessage($"Simulated data: temp={ConvertTempCToUser(currData.tempVal):f1}, hum={currData.humVal}, gust={ConvertWindMPHToUser(currData.windSpeedVal):f2}, dir={currData.windBearingVal}, press={ConvertPressMBToUser(currData.pressureVal):f2}, r.rate={ConvertRainMMToUser(currData.rainRateVal):f2}"); + cumulus.LogDataMessage($"Simulated data: temp={ConvertUnits.TempCToUser(currData.tempVal):f1}, hum={currData.humVal}, gust={ConvertUnits.WindMPHToUser(currData.windSpeedVal):f2}, dir={currData.windBearingVal}, press={ConvertUnits.PressMBToUser(currData.pressureVal):f2}, r.rate={ConvertUnits.RainMMToUser(currData.rainRateVal):f2}"); - DoWind(ConvertWindMPHToUser(currData.windSpeedVal), currData.windBearingVal, -1, recDate); + DoWind(ConvertUnits.WindMPHToUser(currData.windSpeedVal), currData.windBearingVal, -1, recDate); - var rain = Raincounter + ConvertRainMMToUser(currData.rainRateVal * dataUpdateRate / 1000 / 3600); + var rain = RainCounter + ConvertUnits.RainMMToUser(currData.rainRateVal * dataUpdateRate / 1000 / 3600); - DoRain(rain, ConvertRainMMToUser(currData.rainRateVal), recDate); + DoRain(rain, ConvertUnits.RainMMToUser(currData.rainRateVal), recDate); - DoIndoorTemp(ConvertTempCToUser(currData.tempInVal)); + DoIndoorTemp(ConvertUnits.TempCToUser(currData.tempInVal)); DoIndoorHumidity(currData.humInVal); DoOutdoorHumidity(currData.humVal, recDate); - DoOutdoorTemp(ConvertTempCToUser(currData.tempVal), recDate); + DoOutdoorTemp(ConvertUnits.TempCToUser(currData.tempVal), recDate); - DoPressure(ConvertPressMBToUser(currData.pressureVal), recDate); + DoPressure(ConvertUnits.PressMBToUser(currData.pressureVal), recDate); UpdatePressureTrendString(); doSolar(recDate); @@ -270,6 +270,5 @@ public double GetValue(DateTime date) return _value; } } - } } diff --git a/CumulusMX/StationSettings.cs b/CumulusMX/StationSettings.cs index c954e9f3..e9d9f45e 100644 --- a/CumulusMX/StationSettings.cs +++ b/CumulusMX/StationSettings.cs @@ -43,7 +43,7 @@ internal string GetAlpacaFormData() maxwind = cumulus.LCMaxWind, recordtimeout = cumulus.RecordSetTimeoutHrs, snowdepthhour = cumulus.SnowDepthHour, - raindaythreshold = cumulus.RainDayThreshold, + raindaythreshold = cumulus.RainDayThreshold }; // Common Settings @@ -187,7 +187,6 @@ internal string GetAlpacaFormData() summer10am = cumulus.Use10amInSummer }; - var fineoffsetadvanced = new JsonStationSettingsFineOffsetAdvanced() { readtime = cumulus.FineOffsetOptions.ReadTime, @@ -234,7 +233,6 @@ internal string GetAlpacaFormData() advanced = imetAdvanced }; - int deg, min, sec; string hem; @@ -920,7 +918,6 @@ internal string UpdateConfig(IHttpContext context) { if (settings.ecowittmaps != null) { - cumulus.Gw1000PrimaryTHSensor = settings.ecowittmaps.primaryTHsensor; cumulus.Gw1000PrimaryRainSensor = settings.ecowittmaps.primaryRainSensor; @@ -1220,7 +1217,6 @@ internal string UpdateConfig(IHttpContext context) context.Response.StatusCode = 500; } - // Station type try { @@ -1365,6 +1361,7 @@ internal string UploadNow(IHttpContext context) returnMsg = "Error starting a new upload"; cumulus.LogErrorMessage($"Upload Now: {returnMsg}: {ex.Message}"); } + cumulus.LogDebugMessage("Upload Now: Process complete"); return returnMsg; } diff --git a/CumulusMX/TempestStation.cs b/CumulusMX/TempestStation.cs index 5b930354..e12a11d3 100644 --- a/CumulusMX/TempestStation.cs +++ b/CumulusMX/TempestStation.cs @@ -18,8 +18,6 @@ namespace CumulusMX { internal class TempestStation : WeatherStation { - - public TempestStation(Cumulus cumulus) : base(cumulus) { calculaterainrate = false; @@ -131,17 +129,17 @@ private void ProcessHistoryData(List datalist) // Pressure ============================================================= var alt = AltitudeM(cumulus.Altitude); var seaLevel = MeteoLib.GetSeaLevelPressure(alt, (double) historydata.StationPressure, (double) historydata.Temperature); - DoPressure(ConvertPressMBToUser(seaLevel), timestamp); + DoPressure(ConvertUnits.PressMBToUser(seaLevel), timestamp); // Outdoor Humidity ===================================================== DoOutdoorHumidity((int) historydata.Humidity, timestamp); // Wind ================================================================= - DoWind(ConvertWindMSToUser((double) historydata.WindGust), historydata.WindDirection, - ConvertWindMSToUser((double) historydata.WindAverage), timestamp); + DoWind(ConvertUnits.WindMSToUser((double) historydata.WindGust), historydata.WindDirection, + ConvertUnits.WindMSToUser((double) historydata.WindAverage), timestamp); // Outdoor Temperature ================================================== - DoOutdoorTemp(ConvertTempCToUser((double) historydata.Temperature), timestamp); + DoOutdoorTemp(ConvertUnits.TempCToUser((double) historydata.Temperature), timestamp); // add in 'archivePeriod' minutes worth of temperature to the temp samples tempsamplestoday += historydata.ReportInterval; TempTotalToday += OutdoorTemperature * historydata.ReportInterval; @@ -151,16 +149,16 @@ private void ProcessHistoryData(List datalist) // add 1 minute to chill hours ChillHours += historydata.ReportInterval / 60.0; - double rainrate = (double) (ConvertRainMMToUser((double) historydata.Precipitation) * + double rainrate = (double) (ConvertUnits.RainMMToUser((double) historydata.Precipitation) * (60d / historydata.ReportInterval)); - var newRain = Raincounter + ConvertRainMMToUser((double) historydata.Precipitation); + var newRain = RainCounter + ConvertUnits.RainMMToUser((double) historydata.Precipitation); cumulus.LogMessage( $"TempestDoRainHist: New Precip: {historydata.Precipitation}, Type: {historydata.PrecipType}, Rate: {rainrate}, LocalDayRain: {historydata.LocalDayRain}, LocalRainChecked: {historydata.LocalRainChecked}, FinalRainChecked: {historydata.FinalRainChecked}"); DoRain(newRain, rainrate, timestamp); cumulus.LogMessage( - $"TempestDoRainHist: Total Precip for Day: {Raincounter}"); + $"TempestDoRainHist: Total Precip for Day: {RainCounter}"); // calculate dp DoOutdoorDewpoint(-999, timestamp); @@ -211,12 +209,12 @@ private void ProcessHistoryData(List datalist) // OutdoorHumidity, Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex); AddRecentDataWithAq(timestamp, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, - OutdoorHumidity, Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); + OutdoorHumidity, Pressure, RainToday, SolarRad, UV, RainCounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); if (cumulus.StationOptions.CalculatedET && timestamp.Minute == 0) { // Start of a new hour, and we want to calculate ET in Cumulus - CalculateEvaoptranspiration(timestamp); + CalculateEvapotranspiration(timestamp); } DoTrendValues(timestamp); @@ -236,7 +234,6 @@ private void ProcessHistoryData(List datalist) public override void Start() { - cumulus.NormalRunning = true; StationListener.WeatherPacketReceived = WeatherPacketReceived; StationListener.Start(cumulus); @@ -278,33 +275,30 @@ private void WeatherPacketReceived(WeatherPacket wp) DoOutdoorHumidity((int) wp.Observation.Humidity, ts); - var userTemp = ConvertTempCToUser(Convert.ToDouble(wp.Observation.Temperature)); + var userTemp = ConvertUnits.TempCToUser(Convert.ToDouble(wp.Observation.Temperature)); DoOutdoorTemp(userTemp, ts); - DoWind(ConvertWindMSToUser((double) wp.Observation.WindGust), + DoWind(ConvertUnits.WindMSToUser((double) wp.Observation.WindGust), wp.Observation.WindDirection, - ConvertWindMSToUser((double) wp.Observation.WindAverage), + ConvertUnits.WindMSToUser((double) wp.Observation.WindAverage), ts); var alt = AltitudeM(cumulus.Altitude); var seaLevel = MeteoLib.GetSeaLevelPressure(alt, (double) wp.Observation.StationPressure, (double) wp.Observation.Temperature); - DoPressure(ConvertPressMBToUser(seaLevel), ts); - cumulus.LogDebugMessage( - $"TempestPressure: Station:{wp.Observation.StationPressure} mb, Sea Level:{seaLevel} mb, Altitude:{alt}"); + DoPressure(ConvertUnits.PressMBToUser(seaLevel), ts); + cumulus.LogDebugMessage($"TempestPressure: Station:{wp.Observation.StationPressure} mb, Sea Level:{seaLevel} mb, Altitude:{alt}"); DoSolarRad(wp.Observation.SolarRadiation, ts); DoUV((double) wp.Observation.UV, ts); - double rainrate = (double) (ConvertRainMMToUser((double) wp.Observation.Precipitation) * + double rainrate = (double) (ConvertUnits.RainMMToUser((double) wp.Observation.Precipitation) * (60d / wp.Observation.ReportInterval)); - var newRain = Raincounter + ConvertRainMMToUser((double) wp.Observation.Precipitation); - cumulus.LogDebugMessage( - $"TempestDoRain: New Precip: {wp.Observation.Precipitation}, Type: {wp.Observation.PrecipType}, Rate: {rainrate}"); + var newRain = RainCounter + ConvertUnits.RainMMToUser((double) wp.Observation.Precipitation); + cumulus.LogDebugMessage($"TempestDoRain: New Precip: {wp.Observation.Precipitation}, Type: {wp.Observation.PrecipType}, Rate: {rainrate}"); DoRain(newRain, rainrate, ts); - cumulus.LogDebugMessage( - $"TempestDoRain: Total Precip for Day: {Raincounter}"); + cumulus.LogDebugMessage($"TempestDoRain: Total Precip for Day: {RainCounter}"); DoOutdoorDewpoint(-999, ts); DoApparentTemp(ts); @@ -326,7 +320,7 @@ private void WeatherPacketReceived(WeatherPacket wp) var rw = wp.RapidWind; cumulus.LogDataMessage($"Wind Data - speed: {rw.WindSpeed}, direction: {rw.WindDirection}"); - DoWind(ConvertWindMSToUser((double) rw.WindSpeed), + DoWind(ConvertUnits.WindMSToUser((double) rw.WindSpeed), rw.WindDirection, -1, rw.Timestamp); @@ -337,11 +331,10 @@ private void WeatherPacketReceived(WeatherPacket wp) cumulus.LogDebugMessage("Received a Lightning message"); LightningTime = wp.LightningStrike.Timestamp; - LightningDistance = ConvertKmtoUserUnits(wp.LightningStrike.Distance); + LightningDistance = ConvertUnits.KmtoUserUnits(wp.LightningStrike.Distance); LightningStrikesToday++; cumulus.LogDebugMessage($"Lightning Detected: {wp.LightningStrike.Timestamp} - {wp.LightningStrike.Distance} km - {LightningStrikesToday} strikes today"); break; - } } } @@ -632,7 +625,6 @@ public enum RadioStatus public DateTime PacketTime => WeatherPacket.FromUnixTimeSeconds(timestamp); - public int rssi { get; set; } public string hub_sn { get; set; } public List ob { get; set; } diff --git a/CumulusMX/WM918Station.cs b/CumulusMX/WM918Station.cs index f6672171..5f5c456b 100644 --- a/CumulusMX/WM918Station.cs +++ b/CumulusMX/WM918Station.cs @@ -290,8 +290,8 @@ private void WM918Wind(List buff) // Wind Chill W1W2 (WS bit 1 gives sign) // Checksum C1C2 - double current = ConvertWindMSToUser((double) (BCDchartoint(buff[1]) + ((BCDchartoint(buff[2]) % 10) * 100)) / 10); - double average = ConvertWindMSToUser((double) (BCDchartoint(buff[4]) + ((BCDchartoint(buff[5]) % 10) * 100)) / 10); + double current = ConvertUnits.WindMSToUser((double) (BCDchartoint(buff[1]) + ((BCDchartoint(buff[2]) % 10) * 100)) / 10); + double average = ConvertUnits.WindMSToUser((double) (BCDchartoint(buff[4]) + ((BCDchartoint(buff[5]) % 10) * 100)) / 10); int bearing = BCDchartoint(buff[2]) / 10 + (BCDchartoint(buff[3]) * 10); DoWind(current, bearing, average, DateTime.Now); @@ -303,7 +303,7 @@ private void WM918Wind(List buff) if (wc > -70) { - DoWindChill(ConvertTempCToUser(wc), DateTime.Now); + DoWindChill(ConvertUnits.TempCToUser(wc), DateTime.Now); } } @@ -319,12 +319,12 @@ private void WM918Baro(List buff) // Sea-Level pressure S1S2S3S4.SD // Checksum C1C2 - DoOutdoorDewpoint(ConvertTempCToUser(BCDchartoint(buff[18])), DateTime.Now); + DoOutdoorDewpoint(ConvertUnits.TempCToUser(BCDchartoint(buff[18])), DateTime.Now); double locPress = BCDchartoint(buff[1]) + (BCDchartoint(buff[2]) * 100); - StationPressure = ConvertPressMBToUser(locPress); + StationPressure = ConvertUnits.PressMBToUser(locPress); - double pressure = ConvertPressMBToUser((BCDchartoint(buff[3]) / 10) + (BCDchartoint(buff[4]) * 10) + + double pressure = ConvertUnits.PressMBToUser((BCDchartoint(buff[3]) / 10) + (BCDchartoint(buff[4]) * 10) + ((BCDchartoint(buff[5]) % 10) * 1000)); DoPressure(pressure, DateTime.Now); @@ -368,7 +368,7 @@ private void WM918Temp(List buff) if (temp10 > -500) { - DoOutdoorTemp(ConvertTempCToUser(temp10 / 10), DateTime.Now); + DoOutdoorTemp(ConvertUnits.TempCToUser(temp10 / 10), DateTime.Now); } // Indoor temp @@ -376,7 +376,7 @@ private void WM918Temp(List buff) if ((buff[2] & 0x08) == 8) temp10 = -temp10; - DoIndoorTemp(ConvertTempCToUser(temp10 / 10)); + DoIndoorTemp(ConvertUnits.TempCToUser(temp10 / 10)); DoApparentTemp(DateTime.Now); DoFeelsLike(DateTime.Now); @@ -397,8 +397,8 @@ private void WM918Rain(List buff) // Month M1M2) // Checksum C1C2 - double raincounter = ConvertRainMMToUser(BCDchartoint(buff[5]) + (BCDchartoint(buff[6]) * 100)); - double rainrate = ConvertRainMMToUser(BCDchartoint(buff[1]) + ((BCDchartoint(buff[2]) % 10) * 100)); + double raincounter = ConvertUnits.RainMMToUser(BCDchartoint(buff[5]) + (BCDchartoint(buff[6]) * 100)); + double rainrate = ConvertUnits.RainMMToUser(BCDchartoint(buff[1]) + ((BCDchartoint(buff[2]) % 10) * 100)); DoRain(raincounter, rainrate, DateTime.Now); } diff --git a/CumulusMX/WMR100Station.cs b/CumulusMX/WMR100Station.cs index 34dcb282..55eb843a 100644 --- a/CumulusMX/WMR100Station.cs +++ b/CumulusMX/WMR100Station.cs @@ -61,7 +61,7 @@ public WMR100Station(Cumulus cumulus) : base(cumulus) } else { - cumulus.LogMessage("WMR100 station not found!"); + cumulus.LogErrorMessage("WMR100 station not found!"); cumulus.LogConsoleMessage("WMR100 station not found!", ConsoleColor.Red); } } @@ -310,7 +310,7 @@ private void ProcessPondPacket() double num = (sign * ((packetBuffer[4] & 0xF) * 256 + packetBuffer[3])) / 10.0; - WMR200ExtraTempValues[sensor] = ConvertTempCToUser(num); + WMR200ExtraTempValues[sensor] = ConvertUnits.TempCToUser(num); DoExtraTemp(WMR200ExtraTempValues[sensor], sensor); // outdoor dewpoint - n/a @@ -359,7 +359,7 @@ private void ProcessRainPacket() rate = 39.33; } - DoRain(ConvertRainINToUser(counter), ConvertRainINToUser(rate), DateTime.Now); + DoRain(ConvertUnits.RainINToUser(counter), ConvertUnits.RainINToUser(rate), DateTime.Now); // battery status //if PacketBuffer[0] and $40 = $40 then @@ -385,11 +385,11 @@ private void ProcessWindPacket() // average double a = ((packetBuffer[6] * 16) + (packetBuffer[5] / 16)) / 10.0; - DoWind(ConvertWindMSToUser(g), (int) (b), ConvertWindMSToUser(a), now); + DoWind(ConvertUnits.WindMSToUser(g), (int) (b), ConvertUnits.WindMSToUser(a), now); if ((packetBuffer[8] & 0x20) == 0x20) { - // no wind chill, use current temp if (available + // no wind chill, use current temp if available // note that even if (Cumulus is set to calculate wind chill // it can't/won't do it if (temp isn't available, so don't // bother calling anyway @@ -448,7 +448,7 @@ private void ProcessTempPacket() sign = 1; num = (sign * ((packetBuffer[4] & 0xF) * 256 + packetBuffer[3])) / 10.0; - DoOutdoorTemp(ConvertTempCToUser(num), Now); + DoOutdoorTemp(ConvertUnits.TempCToUser(num), Now); // outdoor dewpoint if ((packetBuffer[7] & 0x80) == 0x80) @@ -457,7 +457,7 @@ private void ProcessTempPacket() sign = 1; num = (sign * ((packetBuffer[7] & 0xF) * 256 + packetBuffer[6])) / 10.0; - DoOutdoorDewpoint(ConvertTempCToUser(num), Now); + DoOutdoorDewpoint(ConvertUnits.TempCToUser(num), Now); DoApparentTemp(Now); DoFeelsLike(Now); @@ -483,7 +483,7 @@ private void ProcessTempPacket() sign = 1; num = (sign * ((packetBuffer[4] & 0xF) * 256 + packetBuffer[3])) / 10.0; - DoIndoorTemp(ConvertTempCToUser(num)); + DoIndoorTemp(ConvertUnits.TempCToUser(num)); } if ((sensor > 1) && (sensor < 11)) @@ -502,7 +502,7 @@ private void ProcessTempPacket() num = (sign * ((packetBuffer[4] & 0xF) * 256 + packetBuffer[3])) / 10.0; - WMR200ExtraTempValues[sensor] = ConvertTempCToUser(num); + WMR200ExtraTempValues[sensor] = ConvertUnits.TempCToUser(num); DoExtraTemp(WMR200ExtraTempValues[sensor], sensor); // outdoor dewpoint @@ -512,7 +512,7 @@ private void ProcessTempPacket() sign = 1; num = (sign * ((packetBuffer[7] & 0xF) * 256 + packetBuffer[6])) / 10.0; - WMR200ExtraDPValues[sensor] = ConvertTempCToUser(num); + WMR200ExtraDPValues[sensor] = ConvertUnits.TempCToUser(num); DoExtraDP(WMR200ExtraDPValues[sensor], sensor); ExtraSensorsDetected = true; } @@ -523,11 +523,11 @@ private void ProcessBaroPacket() cumulus.LogDebugMessage("Barometer packet"); double num = ((packetBuffer[5] & 0xF) * 256) + packetBuffer[4]; - double slp = ConvertPressMBToUser(num); + double slp = ConvertUnits.PressMBToUser(num); num = ((packetBuffer[3] & 0xF) * 256) + packetBuffer[2]; - StationPressure = ConvertPressMBToUser(num); + StationPressure = ConvertUnits.PressMBToUser(num); DoPressure(slp, DateTime.Now); diff --git a/CumulusMX/WMR200Station.cs b/CumulusMX/WMR200Station.cs index 90f99a48..9ad7433e 100644 --- a/CumulusMX/WMR200Station.cs +++ b/CumulusMX/WMR200Station.cs @@ -577,7 +577,7 @@ private void ProcessTempHumPacket() } num = sign * ((packetBuffer[9] & 0xF) * 256 + packetBuffer[8]) / 10.0; - DoOutdoorTemp(ConvertTempCToUser(num), now); + DoOutdoorTemp(ConvertUnits.TempCToUser(num), now); // outdoor dewpoint if ((packetBuffer[12] & 0x80) == 0x80) { @@ -588,7 +588,7 @@ private void ProcessTempHumPacket() sign = 1; } num = sign * ((packetBuffer[12] & 0xF) * 256 + packetBuffer[11]) / 10.0; - DoOutdoorDewpoint(ConvertTempCToUser(num), now); + DoOutdoorDewpoint(ConvertUnits.TempCToUser(num), now); DoApparentTemp(now); DoFeelsLike(now); @@ -609,7 +609,7 @@ private void ProcessTempHumPacket() sign = 1; } num = (sign * ((packetBuffer[9] & 0xF) * 256 + packetBuffer[8])) / 10.0; - DoIndoorTemp(ConvertTempCToUser(num)); + DoIndoorTemp(ConvertUnits.TempCToUser(num)); } if ((sensor > 1) && (sensor < 11)) { @@ -627,7 +627,7 @@ private void ProcessTempHumPacket() sign = 1; } - WMR200ExtraTempValues[sensor] = ConvertTempCToUser((sign * ((packetBuffer[9] & 0xF) * 256 + packetBuffer[8])) / 10.0); + WMR200ExtraTempValues[sensor] = ConvertUnits.TempCToUser((sign * ((packetBuffer[9] & 0xF) * 256 + packetBuffer[8])) / 10.0); DoExtraTemp(WMR200ExtraTempValues[sensor], sensor); // outdoor dewpoint if ((packetBuffer[12] & 0x80) == 0x80) @@ -639,7 +639,7 @@ private void ProcessTempHumPacket() sign = 1; } - WMR200ExtraDPValues[sensor] = ConvertTempCToUser((sign * ((packetBuffer[12] & 0xF) * 256 + packetBuffer[11])) / 10.0); + WMR200ExtraDPValues[sensor] = ConvertUnits.TempCToUser((sign * ((packetBuffer[12] & 0xF) * 256 + packetBuffer[11])) / 10.0); DoExtraDP(WMR200ExtraDPValues[sensor], sensor); ExtraSensorsDetected = true; } @@ -857,7 +857,7 @@ private void ProcessWindPacket() // average double average = ((packetBuffer[11] * 16) + (packetBuffer[10] / 16)) / 10.0; - DoWind(ConvertWindMSToUser(gust), bearing, ConvertWindMSToUser(average), now); + DoWind(ConvertUnits.WindMSToUser(gust), bearing, ConvertUnits.WindMSToUser(average), now); if ((packetBuffer[13] & 0x20) == 0x20) { @@ -947,9 +947,9 @@ private void ProcessBaroPacket() //Byte 12: (cH) Check-sum high byte double slp = ((packetBuffer[10] & 0xF) * 256) + packetBuffer[9]; - DoPressure(ConvertPressMBToUser(slp), DateTime.Now); + DoPressure(ConvertUnits.PressMBToUser(slp), DateTime.Now); - StationPressure = ConvertPressMBToUser(((packetBuffer[8] & 0xF) * 256) + packetBuffer[7]); + StationPressure = ConvertUnits.PressMBToUser(((packetBuffer[8] & 0xF) * 256) + packetBuffer[7]); UpdatePressureTrendString(); @@ -1434,9 +1434,9 @@ private void ProcessHistoryDataPacket() } previousHistoryTimeStamp = timestamp; // pressure - StationPressure = ConvertPressMBToUser(((packetBuffer[29] & 0xF) * 256) + packetBuffer[28]); + StationPressure = ConvertUnits.PressMBToUser(((packetBuffer[29] & 0xF) * 256) + packetBuffer[28]); double num = ((packetBuffer[31] & 0xF) * 256) + packetBuffer[30]; - DoPressure(ConvertPressMBToUser(num), timestamp); + DoPressure(ConvertUnits.PressMBToUser(num), timestamp); // bearing int bearing = (int) ((packetBuffer[20] & 0xF) * 22.5); @@ -1445,7 +1445,7 @@ private void ProcessHistoryDataPacket() // average double average = ((packetBuffer[24] * 16) + (packetBuffer[23] / 16)) / 10.0; - DoWind(ConvertWindMSToUser(gust), bearing, ConvertWindMSToUser(average), timestamp); + DoWind(ConvertUnits.WindMSToUser(gust), bearing, ConvertUnits.WindMSToUser(average), timestamp); // add in 'interval' minutes worth of wind speed to windrun WindRunToday += (WindAverage * WindRunHourMult[cumulus.Units.Wind] * interval * 60) / 1000.0; @@ -1473,7 +1473,7 @@ private void ProcessHistoryDataPacket() { sign = 1; } - DoIndoorTemp(ConvertTempCToUser(sign * ((packetBuffer[offset + 2] & 0xF) * 256 + packetBuffer[offset + 1])) / 10.0); + DoIndoorTemp(ConvertUnits.TempCToUser(sign * ((packetBuffer[offset + 2] & 0xF) * 256 + packetBuffer[offset + 1])) / 10.0); } else if (sensornumber == cumulus.WMR200TempChannel) { @@ -1489,7 +1489,7 @@ private void ProcessHistoryDataPacket() { sign = 1; } - DoOutdoorTemp(ConvertTempCToUser((sign * ((packetBuffer[offset + 2] & 0xF) * 256 + packetBuffer[offset + 1])) / 10.0), timestamp); + DoOutdoorTemp(ConvertUnits.TempCToUser((sign * ((packetBuffer[offset + 2] & 0xF) * 256 + packetBuffer[offset + 1])) / 10.0), timestamp); // update heating/cooling degree days UpdateDegreeDays(interval); @@ -1515,7 +1515,7 @@ private void ProcessHistoryDataPacket() sign = 1; } - DoOutdoorDewpoint(ConvertTempCToUser((sign * ((packetBuffer[offset + 5] & 0xF) * 256 + packetBuffer[offset + 4])) / 10.0), timestamp); + DoOutdoorDewpoint(ConvertUnits.TempCToUser((sign * ((packetBuffer[offset + 5] & 0xF) * 256 + packetBuffer[offset + 4])) / 10.0), timestamp); } if (sensornumber > 1 && sensornumber < 11) @@ -1534,7 +1534,7 @@ private void ProcessHistoryDataPacket() sign = 1; } - DoExtraTemp(ConvertTempCToUser((sign * ((packetBuffer[offset + 2] & 0xF) * 256 + packetBuffer[offset + 1])) / 10.0), sensornumber); + DoExtraTemp(ConvertUnits.TempCToUser((sign * ((packetBuffer[offset + 2] & 0xF) * 256 + packetBuffer[offset + 1])) / 10.0), sensornumber); // dew point if ((packetBuffer[offset + 5] & 0x80) == 0x80) @@ -1546,7 +1546,7 @@ private void ProcessHistoryDataPacket() sign = 1; } - DoExtraDP(ConvertTempCToUser((sign * ((packetBuffer[offset + 5] & 0xF) * 256 + packetBuffer[offset + 4])) / 10.0), sensornumber); + DoExtraDP(ConvertUnits.TempCToUser((sign * ((packetBuffer[offset + 5] & 0xF) * 256 + packetBuffer[offset + 4])) / 10.0), sensornumber); } } catch (Exception ex) @@ -1585,7 +1585,7 @@ private void ProcessHistoryDataPacket() var rate = ((packetBuffer[8] * 256) + packetBuffer[7]) / 100.0; - DoRain(ConvertRainINToUser(counter), ConvertRainINToUser(rate), timestamp); + DoRain(ConvertUnits.RainINToUser(counter), ConvertUnits.RainINToUser(rate), timestamp); // UV if (packetBuffer[27] != 0xFF) @@ -1612,7 +1612,7 @@ private void ProcessHistoryDataPacket() } AddRecentDataEntry(timestamp, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, OutdoorHumidity, - Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate, -1, -1); + Pressure, RainToday, SolarRad, UV, RainCounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate, -1, -1); DoTrendValues(timestamp); UpdatePressureTrendString(); UpdateStatusPanel(timestamp); diff --git a/CumulusMX/WMR928Station.cs b/CumulusMX/WMR928Station.cs index 69d0bf5e..335f4162 100644 --- a/CumulusMX/WMR928Station.cs +++ b/CumulusMX/WMR928Station.cs @@ -303,7 +303,7 @@ private void WMR928ExtraTempOnly(List buff) double temp = ExtractTemp(buff[4], buff[5]); - WMR928ExtraTempValues[channel] = ConvertTempCToUser(temp); + WMR928ExtraTempValues[channel] = ConvertUnits.TempCToUser(temp); DoExtraTemp(WMR928ExtraTempValues[channel], channel); if (cumulus.WMR928TempChannel == channel) @@ -371,11 +371,11 @@ private void WMR928ExtraOutdoor(List buff) double temp = ExtractTemp(buff[4], buff[5]); - WMR928ExtraTempValues[channel] = ConvertTempCToUser(temp); + WMR928ExtraTempValues[channel] = ConvertUnits.TempCToUser(temp); DoExtraTemp(WMR928ExtraTempValues[channel], channel); - WMR928ExtraDPValues[channel] = ConvertTempCToUser(BCDchartoint(buff[7])); - ExtraDewPoint[channel] = ConvertTempCToUser(BCDchartoint(buff[7])); + WMR928ExtraDPValues[channel] = ConvertUnits.TempCToUser(BCDchartoint(buff[7])); + ExtraDewPoint[channel] = ConvertUnits.TempCToUser(BCDchartoint(buff[7])); if (cumulus.WMR928TempChannel == channel) { @@ -385,9 +385,9 @@ private void WMR928ExtraOutdoor(List buff) // Extract humidity DoOutdoorHumidity(BCDchartoint(buff[6]), DateTime.Now); - DoOutdoorTemp(ConvertTempCToUser(temp), DateTime.Now); + DoOutdoorTemp(ConvertUnits.TempCToUser(temp), DateTime.Now); - DoOutdoorDewpoint(ConvertTempCToUser(BCDchartoint(buff[7])), DateTime.Now); + DoOutdoorDewpoint(ConvertUnits.TempCToUser(BCDchartoint(buff[7])), DateTime.Now); } } @@ -409,14 +409,14 @@ private void WMR928Wind(List buff) double average = (double) (BCDchartoint(buff[7]) + ((BCDchartoint(buff[8]) % 10) * 100)) / 10; int bearing = BCDchartoint(buff[4]) + ((BCDchartoint(buff[5]) % 10) * 100); - DoWind(ConvertWindMSToUser(current), bearing, ConvertWindMSToUser(average), DateTime.Now); + DoWind(ConvertUnits.WindMSToUser(current), bearing, ConvertUnits.WindMSToUser(average), DateTime.Now); // Extract wind chill double wc = BCDchartoint(buff[9]); if (buff[9] / 16 == 8) wc = -wc; - DoWindChill(ConvertTempCToUser(wc), DateTime.Now); + DoWindChill(ConvertUnits.TempCToUser(wc), DateTime.Now); } private void WMR928Rain(List buff) @@ -439,8 +439,8 @@ private void WMR928Rain(List buff) RainBattStatus = buff[3] / 16; // MainForm.Rainbatt.Position := (15-rain_batt_status)*100 DIV 15; - double raincounter = ConvertRainMMToUser(BCDchartoint(buff[6]) + (BCDchartoint(buff[7]) * 100)); - double rainrate = ConvertRainMMToUser(BCDchartoint(buff[4]) + ((BCDchartoint(buff[5]) % 10) * 100)); + double raincounter = ConvertUnits.RainMMToUser(BCDchartoint(buff[6]) + (BCDchartoint(buff[7]) * 100)); + double rainrate = ConvertUnits.RainMMToUser(BCDchartoint(buff[4]) + ((BCDchartoint(buff[5]) % 10) * 100)); DoRain(raincounter, rainrate, DateTime.Now); } @@ -468,10 +468,10 @@ private void WMR928Outdoor(List buff) // Extract temperature double temp = ExtractTemp(buff[4], buff[5]); - DoOutdoorTemp(ConvertTempCToUser(temp), DateTime.Now); + DoOutdoorTemp(ConvertUnits.TempCToUser(temp), DateTime.Now); // Extract dewpoint - DoOutdoorDewpoint(ConvertTempCToUser(BCDchartoint(buff[7])), DateTime.Now); + DoOutdoorDewpoint(ConvertUnits.TempCToUser(BCDchartoint(buff[7])), DateTime.Now); DoApparentTemp(DateTime.Now); DoFeelsLike(DateTime.Now); @@ -507,11 +507,11 @@ private void WMR928Indoor(List buff) // local pressure (not BCD); byte 8, with 856mb offset double loc = buff[8] + 856; - StationPressure = ConvertPressMBToUser(loc); + StationPressure = ConvertUnits.PressMBToUser(loc); double num = BCDchartoint((buff[10]) / 10) + BCDchartoint(buff[11]) * 10 + (BCDchartoint(buff[12]) * 1000); double slcorr = num / 10.0 - 600; - DoPressure(ConvertPressMBToUser(loc + slcorr), DateTime.Now); + DoPressure(ConvertUnits.PressMBToUser(loc + slcorr), DateTime.Now); UpdatePressureTrendString(); @@ -566,7 +566,7 @@ private void WMR928Indoor2(List buff) // local pressure (not BCD); byte 8, with 795mb offset double loc = buff[8] + 795; - StationPressure = ConvertPressMBToUser(loc); + StationPressure = ConvertUnits.PressMBToUser(loc); // SL pressure correction; bytes 10 (LSB) and 11 (MSB) double num = BCDchartoint(buff[10] / 10) + (BCDchartoint(buff[11]) * 10) + buff[8]; DoPressure(num, DateTime.Now); diff --git a/CumulusMX/WS2300Station.cs b/CumulusMX/WS2300Station.cs index bccc30b6..9849c414 100644 --- a/CumulusMX/WS2300Station.cs +++ b/CumulusMX/WS2300Station.cs @@ -221,7 +221,7 @@ private void ProcessHistoryData() double prevraintotal = -1; double raindiff, rainrate; - double pressureoffset = ConvertPressMBToUser(Ws2300PressureOffset()); + double pressureoffset = ConvertUnits.PressMBToUser(Ws2300PressureOffset()); while (datalist.Count > 0) { @@ -320,20 +320,20 @@ private void ProcessHistoryData() // Dewpoint ==================================================================== if (cumulus.StationOptions.CalculatedDP) { - double tempC = ConvertUserTempToC(OutdoorTemperature); - DoOutdoorDewpoint(ConvertTempCToUser(MeteoLib.DewPoint(tempC, OutdoorHumidity)), timestamp); + double tempC = ConvertUnits.UserTempToC(OutdoorTemperature); + DoOutdoorDewpoint(ConvertUnits.TempCToUser(MeteoLib.DewPoint(tempC, OutdoorHumidity)), timestamp); CheckForDewpointHighLow(timestamp); } else { - if (historydata.dewpoint < ConvertUserTempToC(60)) + if (historydata.dewpoint < ConvertUnits.UserTempToC(60)) { DoOutdoorDewpoint(cumulus.Calib.Temp.Calibrate(historydata.dewpoint), timestamp); } } // Wind chill ================================================================== - if (historydata.windchill < ConvertTempCToUser(60)) + if (historydata.windchill < ConvertUnits.TempCToUser(60)) { DoWindChill(historydata.windchill, timestamp); } @@ -353,7 +353,7 @@ private void ProcessHistoryData() // Pressure ====================================================================== double slpress = historydata.pressure + pressureoffset; - if ((slpress > ConvertPressMBToUser(900)) && (slpress < ConvertPressMBToUser(1200))) + if ((slpress > ConvertUnits.PressMBToUser(900)) && (slpress < ConvertUnits.PressMBToUser(1200))) { DoPressure(slpress, timestamp); } @@ -381,7 +381,7 @@ private void ProcessHistoryData() } cumulus.MySqlRealtimeFile(999, false, timestamp); - AddRecentDataEntry(timestamp, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, OutdoorHumidity, Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, rainrate, -1, -1); + AddRecentDataEntry(timestamp, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, OutdoorHumidity, Pressure, RainToday, SolarRad, UV, RainCounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, rainrate, -1, -1); UpdatePressureTrendString(); UpdateStatusPanel(timestamp); cumulus.AddToWebServiceLists(timestamp); @@ -549,13 +549,13 @@ private int Ws2300ReadHistoryRecord(int record, out int address, out double temp if (pressure >= 1502.2) pressure -= 1000; - pressure = ConvertPressMBToUser(pressure); + pressure = ConvertUnits.PressMBToUser(pressure); humindoor = (int) ((tempint - (tempint % 10000)) / 10000.0); humoutdoor = (data[5] >> 4) * 10 + (data[5] & 0xF); - raincount = ConvertRainMMToUser(rainref + (((data[7] & 0xF) * 256 + data[6]) - raincountref) * 0.518); + raincount = ConvertUnits.RainMMToUser(rainref + (((data[7] & 0xF) * 256 + data[6]) - raincountref) * 0.518); windspeed = (data[8] * 16 + (data[7] >> 4)) / 10.0; @@ -569,15 +569,15 @@ private int Ws2300ReadHistoryRecord(int record, out int address, out double temp double windkmh = 3.6 * windspeed; tempint = ((data[2] & 0xF) << 16) + (data[1] << 8) + data[0]; - tempindoor = ConvertTempCToUser((tempint % 1000) / 10.0f - 30.0); + tempindoor = ConvertUnits.TempCToUser((tempint % 1000) / 10.0f - 30.0); tempoutdoor = (tempint - (tempint % 1000)) / 10000.0f - 30.0; - windchill = ConvertTempCToUser(MeteoLib.WindChill(tempoutdoor, windkmh)); - dewpoint = ConvertTempCToUser(MeteoLib.DewPoint(tempoutdoor, humoutdoor)); + windchill = ConvertUnits.TempCToUser(MeteoLib.WindChill(tempoutdoor, windkmh)); + dewpoint = ConvertUnits.TempCToUser(MeteoLib.DewPoint(tempoutdoor, humoutdoor)); - tempoutdoor = ConvertTempCToUser(tempoutdoor); + tempoutdoor = ConvertUnits.TempCToUser(tempoutdoor); - windspeed = ConvertWindMSToUser(windspeed); + windspeed = ConvertUnits.WindMSToUser(windspeed); winddir = (data[9] & 0xF) * 22.5; return (++record) % 0xAF; @@ -617,7 +617,7 @@ private void GetAndProcessData() double intemp = Ws2300IndoorTemperature(); if (intemp > -20) { - DoIndoorTemp(ConvertTempCToUser(intemp)); + DoIndoorTemp(ConvertUnits.TempCToUser(intemp)); } } @@ -628,7 +628,7 @@ private void GetAndProcessData() if ((outtemp > -60) && (outtemp < 60) && ((previoustemp == 999) || (Math.Abs(outtemp - previoustemp) < cumulus.Spike.TempDiff))) { previoustemp = outtemp; - DoOutdoorTemp(ConvertTempCToUser(outtemp), now); + DoOutdoorTemp(ConvertUnits.TempCToUser(outtemp), now); } } @@ -638,7 +638,7 @@ private void GetAndProcessData() double dp = Ws2300OutdoorDewpoint(); if (dp > -100 && dp < 60) { - DoOutdoorDewpoint(ConvertTempCToUser(dp), now); + DoOutdoorDewpoint(ConvertUnits.TempCToUser(dp), now); } } @@ -649,14 +649,14 @@ private void GetAndProcessData() if ((pressure > 900) && (pressure < 1200) && ((previouspress == 9999) || (Math.Abs(pressure - previouspress) < cumulus.Spike.PressDiff))) { previouspress = pressure; - DoPressure(ConvertPressMBToUser(pressure), now); + DoPressure(ConvertUnits.PressMBToUser(pressure), now); } pressure = Ws2300AbsolutePressure(); if ((Pressure > 850) && (Pressure < 1200)) { - StationPressure = ConvertPressMBToUser(cumulus.Calib.Press.Calibrate(pressure)); + StationPressure = ConvertUnits.PressMBToUser(cumulus.Calib.Press.Calibrate(pressure)); // AltimeterPressure := ConvertOregonPress(StationToAltimeter(PressureHPa(StationPressure),AltitudeM(Altitude))); } } @@ -679,7 +679,7 @@ private void GetAndProcessData() if ((wind > -1) && ((previouswind == 999) || (Math.Abs(wind - previouswind) < cumulus.Spike.WindDiff))) { previouswind = wind; - DoWind(ConvertWindMSToUser(wind), (int) direction, -1, now); + DoWind(ConvertUnits.WindMSToUser(wind), (int) direction, -1, now); } else { @@ -691,7 +691,7 @@ private void GetAndProcessData() double wc = Ws2300WindChill(); if (wc > -100 && wc < 60) { - DoWindChill(ConvertTempCToUser(wc), now); + DoWindChill(ConvertUnits.TempCToUser(wc), now); } } @@ -701,7 +701,7 @@ private void GetAndProcessData() double raintot = Ws2300RainTotal(); if (raintot > -1) { - DoRain(ConvertRainMMToUser(raintot), -1, now); + DoRain(ConvertUnits.RainMMToUser(raintot), -1, now); } } diff --git a/CumulusMX/WeatherLink.cs b/CumulusMX/WeatherLink.cs index c22ad6ad..b1d29446 100644 --- a/CumulusMX/WeatherLink.cs +++ b/CumulusMX/WeatherLink.cs @@ -617,8 +617,8 @@ public VPArchiveData() // internal void Process(DavisStation station) // Processes the archive data once it's been loaded // { - /* station.IndoorTemperature = station.ConvertTempFToUser(InsideTemperature); - station.OutdoorTemperature = station.ConvertTempFToUser(OutsideTemperature); + /* station.IndoorTemperature = ConvertUnits.TempFToUser(InsideTemperature); + station.OutdoorTemperature = ConvertUnits.TempFToUser(OutsideTemperature); station.IndoorHumidity = InsideHumidity; station.OutdoorHumidity = OutsideHumidity; station.Pressure = station.ConvertPressToInternal(Pressure); @@ -631,7 +631,7 @@ public VPArchiveData() station.UV = AvgUVIndex; station.SolarRad = SolarRad; - station.ET = station.ConvertRainMMToUser(ET); + station.ET = ConvertUnits.RainMMToUser(ET); station.ExtraHum[1] = ExtraHum1; station.ExtraHum[2] = ExtraHum2; diff --git a/CumulusMX/WeatherStation.cs b/CumulusMX/WeatherStation.cs index e362412d..d3856a75 100644 --- a/CumulusMX/WeatherStation.cs +++ b/CumulusMX/WeatherStation.cs @@ -182,6 +182,7 @@ public struct dayfilerec private int lastMinute; private int lastHour; + private int lastSecond; public bool[] WMR928ChannelPresent = new[] { false, false, false, false }; public bool[] WMR928ExtraTempValueOnly = new[] { false, false, false, false }; @@ -217,8 +218,8 @@ public struct dayfilerec public double THWIndex = 0; public double THSWIndex = 0; - public double raindaystart = 0.0; - public double Raincounter = 0.0; + public double RainCounterDayStart = 0.0; + public double RainCounter = 0.0; public bool gotraindaystart = false; protected double prevraincounter = 0.0; @@ -383,11 +384,23 @@ public virtual string GetEcowittCameraUrl() return string.Empty; } - public WeatherStation(Cumulus cumulus) + public virtual string GetEcowittVideoUrl() + { + return string.Empty; + } + + + public WeatherStation(Cumulus cumulus, bool extraStation = false) { // save the reference to the owner this.cumulus = cumulus; + // if we are an extra station, then don't do any of the "normal" intialisation + if (extraStation) + { + return; + } + // initialise the monthly array of records - element zero is not used for (var i = 1; i <= 12; i++) { @@ -522,18 +535,35 @@ public void ReloadFailedMySQLCommands() private void GetRainCounter() { + // do we need to do anything? + if (!initialiseRainCounter && !initialiseMidnightRain && !initialiseRainDayStart) + { + cumulus.LogMessage("GetRainCounter: Nothing to do"); + return; + } + // Find today's rain so far from last record in log file + bool raindaystartfound = false; + bool raincounterfound = false; bool midnightrainfound = false; - //string LogFile = cumulus.Datapath + cumulus.LastUpdateTime.ToString("MMMyy") + "log.txt"; + string LogFile = cumulus.GetLogFileName(cumulus.LastUpdateTime); - double raincount = 0; + double raintoday = 0; + double raincounter = 0; + double midnightraincounter = 0; + double raindaystart = 0; + string logdate = "00/00/00"; string prevlogdate = "00/00/00"; + string listSep = CultureInfo.CurrentCulture.TextInfo.ListSeparator; string todaydatestring = cumulus.LastUpdateTime.ToString("dd/MM/yy"); - cumulus.LogMessage("Finding raintoday from logfile " + LogFile); - cumulus.LogMessage("Expecting listsep=" + listSep + " decimal=" + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator); + var lastDate = cumulus.LastUpdateTime.AddHours(cumulus.GetHourInc(cumulus.LastUpdateTime)); + var meteoDate = new DateTime(lastDate.Year, lastDate.Month, lastDate.Day, -cumulus.GetHourInc(cumulus.LastUpdateTime), 0, 0); + + cumulus.LogMessage("GetRainCounter: Finding raintoday from logfile " + LogFile); + cumulus.LogMessage("GetRainCounter: Expecting listsep=" + listSep + " decimal=" + CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator); if (File.Exists(LogFile)) { @@ -549,89 +579,124 @@ private void GetRainCounter() var st = new List(Regex.Split(line, listSep)); if (st.Count > 0) { - RainToday = Double.Parse(st[9]); + raintoday = Double.Parse(st[9]); + raincounter = Double.Parse(st[11]); + + raincounterfound = true; + // get date of this entry logdate = st[0]; - if (!midnightrainfound) + + if (logdate != prevlogdate && todaydatestring == logdate) { - if (logdate != prevlogdate) + if ((initialiseMidnightRain && !midnightrainfound) || (cumulus.RolloverHour == 0 && initialiseRainDayStart && !raindaystartfound)) { - if (todaydatestring == logdate) + if (initialiseMidnightRain) { // this is the first entry of a new day AND the new day is today midnightrainfound = true; - cumulus.LogMessage("Midnight rain found in the following entry:"); - cumulus.LogMessage(line); - raincount = Double.Parse(st[11]); + midnightraincounter = Double.Parse(st[11]) - Double.Parse(st[9]); + cumulus.LogMessage($"GetRainCounter: Midnight rain counter {midnightraincounter:F4} found in the following entry:"); } + + if (initialiseRainDayStart) + { + raindaystartfound = true; + raindaystart = Double.Parse(st[11]) - Double.Parse(st[9]); + cumulus.LogMessage($"GetRainCounter: Rain day start counter {raindaystart:F4} found in the following entry:"); + } + cumulus.LogMessage(line); + } + } + + if (initialiseRainDayStart && !raindaystartfound && cumulus.RolloverHour != 0) + { + var logDateTime = Utils.ddmmyyhhmmStrToDate(st[0], st[1]); + if (logDateTime >= meteoDate) + { + raindaystartfound = true; + raindaystart = Double.Parse(st[11]) - Double.Parse(st[9]); + cumulus.LogMessage($"GetRainCounter: Rain day start counter {raindaystart:F4} found in the following entry:"); + cumulus.LogMessage(line); } } + prevlogdate = logdate; } } } catch (Exception E) { - cumulus.LogErrorMessage("Error on line " + linenum + " of " + LogFile + ": " + E.Message); + cumulus.LogErrorMessage("GetRainCounter: Error on line " + linenum + " of " + LogFile + ": " + E.Message); } } - if (midnightrainfound) + if (initialiseMidnightRain) { - if ((logdate.Substring(0, 2) == "01") && (logdate.Substring(3, 2) == cumulus.RainSeasonStart.ToString("D2")) && (cumulus.Manufacturer == cumulus.DAVIS)) + if (midnightrainfound) { - // special case: rain counter is about to be reset - //TODO: MC: Hmm are there issues here, what if the console clock is wrong and it does not reset for another hour, or it already reset and we have had rain since? - var month = CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(cumulus.RainSeasonStart); - cumulus.LogMessage($"Special case, Davis station on 1st of {month}. Set midnight rain count to zero"); - midnightraincount = 0; + if (Math.Round(MidnightRainCount, cumulus.RainDPlaces) == Math.Round(midnightraincounter, cumulus.RainDPlaces)) + { + cumulus.LogMessage($"GetRainCounter: Rain day start counter {RainCounterDayStart:F4} and midnight rain counter {midnightraincounter:F4} match within rounding error, setting midnight rain to rain day start value"); + MidnightRainCount = RainCounterDayStart; + } + else + { + cumulus.LogMessage($"GetRainCounter: Midnight rain counter found, setting existing midnight rain counter {MidnightRainCount:F4} to log file value {midnightraincounter:F4}"); + MidnightRainCount = midnightraincounter; + } } else { - cumulus.LogMessage("Midnight rain found, setting midnight rain count = " + raincount); - midnightraincount = raincount; + cumulus.LogMessage("GetRainCounter: Midnight rain counter not found, setting midnight count to raindaystart = " + RainCounterDayStart); + MidnightRainCount = RainCounterDayStart; } - } - else - { - cumulus.LogMessage("Midnight rain not found, setting midnight count to raindaystart = " + raindaystart); - midnightraincount = raindaystart; + + initialiseMidnightRain = false; } - // If we do not have a rain counter value for start of day from Today.ini, then use the midnight counter - if (initialiseRainCounterOnFirstData) + if ((logdate.Substring(0, 2) == "01") && (logdate.Substring(3, 2) == cumulus.RainSeasonStart.ToString("D2")) && (cumulus.Manufacturer == cumulus.DAVIS)) { - Raincounter = midnightraincount + (RainToday / cumulus.Calib.Rain.Mult); + // special case: rain counter is about to be reset + //TODO: MC: Hmm are there issues here, what if the console clock is wrong and it does not reset for another hour, or it already reset and we have had rain since? + var month = CultureInfo.InvariantCulture.DateTimeFormat.GetMonthName(cumulus.RainSeasonStart); + cumulus.LogMessage($"GetRainCounter: Special case, Davis station on 1st of {month}. Set midnight rain count to zero"); + MidnightRainCount = 0; } - else + + if (initialiseRainDayStart && raindaystartfound) { - // Otherwise use the counter value from today.ini plus total so far today to infer the counter value - Raincounter = raindaystart + (RainToday / cumulus.Calib.Rain.Mult); + cumulus.LogMessage($"GetRainCounter: Rain day start counter found, setting existing start rain counter {RainCounterDayStart:F4} to log file value {raindaystart:F4}"); + RainCounterDayStart = raindaystart; + initialiseRainDayStart = false; } - cumulus.LogMessage("Checking rain counter = " + Raincounter); - if (Raincounter < 0) + // If we do not have a rain counter value for start of day from Today.ini, then use the last value from the log file + if (initialiseRainCounter && raincounterfound) { - cumulus.LogMessage("Rain counter negative, setting to zero"); - Raincounter = 0; + cumulus.LogMessage($"GetRainCounter: Rain counter found, setting existing rain counter {RainCounter:F4} to log file value {raincounter:F4}"); + RainCounter = raincounter; + initialiseRainCounter = false; } - else + + if (RainCounter < 0) { - cumulus.LogMessage("Rain counter set to = " + Raincounter); + cumulus.LogMessage("GetRainCounter: Rain counter negative, setting to zero"); + RainCounter = 0; } } public void GetRainFallTotals() { - cumulus.LogMessage("Getting rain totals, rain season start = " + cumulus.RainSeasonStart); - rainthismonth = 0; - rainthisyear = 0; + cumulus.LogMessage("GetRainFallTotals: Getting rain totals, rain season start = " + cumulus.RainSeasonStart); + RainThisMonth = 0; + RainThisYear = 0; // get today's date for month check; allow for 0900 roll-over var hourInc = cumulus.GetHourInc(); var ModifiedNow = DateTime.Now.AddHours(hourInc); // avoid any funny locale peculiarities on date formats string Today = ModifiedNow.ToString("dd/MM/yy", CultureInfo.InvariantCulture); - cumulus.LogMessage("Today = " + Today); + cumulus.LogMessage("GetRainFallTotals: Today = " + Today); // get today's date offset by rain season start for year check int offsetYearToday = ModifiedNow.AddMonths(-(cumulus.RainSeasonStart - 1)).Year; @@ -643,12 +708,12 @@ public void GetRainFallTotals() // This year? if (offsetLoggedYear == offsetYearToday) { - rainthisyear += rec.TotalRain; + RainThisYear += rec.TotalRain; } // This month? if ((rec.Date.Month == ModifiedNow.Month) && (rec.Date.Year == ModifiedNow.Year)) { - rainthismonth += rec.TotalRain; + RainThisMonth += rec.TotalRain; } } } @@ -657,26 +722,25 @@ public void GetRainFallTotals() cumulus.LogMessage("GetRainfallTotals: Error - " + ex.Message); } - cumulus.LogMessage("Rainthismonth from dayfile: " + rainthismonth); - cumulus.LogMessage("Rainthisyear from dayfile: " + rainthisyear); + cumulus.LogMessage("GetRainFallTotals: Rainthismonth from dayfile: " + RainThisMonth); + cumulus.LogMessage("GetRainFallTotals: Rainthisyear from dayfile: " + RainThisYear); // Add in year-to-date rain (if necessary) if (cumulus.YTDrainyear == Convert.ToInt32(Today.Substring(6, 2)) + 2000) { - cumulus.LogMessage("Adding YTD rain: " + cumulus.YTDrain); - rainthisyear += cumulus.YTDrain; - cumulus.LogMessage("Rainthisyear: " + rainthisyear); + cumulus.LogMessage($"GetRainFallTotals: Adding YTD rain: {cumulus.YTDrain}, new Rainthisyear: {RainThisYear}"); + RainThisYear += cumulus.YTDrain; } - RainMonth = rainthismonth; - RainYear = rainthisyear; + RainMonth = RainThisMonth; + RainYear = RainThisYear; } public void UpdateYearMonthRainfall() { var _month = RainMonth; var _year = RainYear; - RainMonth = rainthismonth + RainToday; - RainYear = rainthisyear + RainToday; + RainMonth = RainThisMonth + RainToday; + RainYear = RainThisYear + RainToday; cumulus.LogMessage($"Rainthismonth Updated from: {_month.ToString(cumulus.RainFormat)} to: {RainMonth.ToString(cumulus.RainFormat)}"); cumulus.LogMessage($"Rainthisyear Updated from: {_year.ToString(cumulus.RainFormat)} to: {RainYear.ToString(cumulus.RainFormat)}"); @@ -691,17 +755,15 @@ public void ReadTodayFile() IniFile ini = new IniFile(cumulus.TodayIniFile); - cumulus.LogConsoleMessage("Today.ini = " + cumulus.TodayIniFile); - var todayfiledate = ini.GetValue("General", "Date", "00/00/00"); var timestampstr = ini.GetValue("General", "Timestamp", DateTime.Now.ToString("s")); - cumulus.LogConsoleMessage("Last update=" + timestampstr); + cumulus.LogConsoleMessage("Last update: " + timestampstr); cumulus.LastUpdateTime = DateTime.Parse(timestampstr); var todayDate = cumulus.LastUpdateTime.Date; - cumulus.LogMessage("Last update time from today.ini: " + cumulus.LastUpdateTime); + cumulus.LogMessage("ReadTodayFile: Last update time from today.ini: " + cumulus.LastUpdateTime); DateTime metoTodayDate = cumulus.LastUpdateTime.AddHours(cumulus.GetHourInc()).Date; @@ -713,7 +775,7 @@ public void ReadTodayFile() CurrentMonth = ini.GetValue("General", "CurrentMonth", defaultmonth); CurrentDay = ini.GetValue("General", "CurrentDay", defaultday); - cumulus.LogMessage("Read today file: Date = " + todayfiledate + ", LastUpdateTime = " + cumulus.LastUpdateTime + ", Month = " + CurrentMonth); + cumulus.LogMessage("ReadTodayFile: Date = " + todayfiledate + ", LastUpdateTime = " + cumulus.LastUpdateTime + ", Month = " + CurrentMonth); LastRainTip = ini.GetValue("Rain", "LastTip", "0000-00-00 00:00"); @@ -722,8 +784,8 @@ public void ReadTodayFile() FOSolarClockTime = ini.GetValue("FineOffset", "FOSolarClockTime", DateTime.MinValue); if (cumulus.FineOffsetOptions.SyncReads && (cumulus.StationType == StationTypes.FineOffset || cumulus.StationType == StationTypes.FineOffsetSolar)) { - cumulus.LogMessage("Sensor clock " + FOSensorClockTime.ToLongTimeString()); - cumulus.LogMessage("Station clock " + FOStationClockTime.ToLongTimeString()); + cumulus.LogMessage("ReadTodayFile: Sensor clock " + FOSensorClockTime.ToLongTimeString()); + cumulus.LogMessage("ReadTodayFile: Station clock " + FOStationClockTime.ToLongTimeString()); } ConsecutiveRainDays = ini.GetValue("Rain", "ConsecutiveRainDays", 0); ConsecutiveDryDays = ini.GetValue("Rain", "ConsecutiveDryDays", 0); @@ -732,13 +794,13 @@ public void ReadTodayFile() StartofdayET = ini.GetValue("ET", "Startofday", -1.0); if (StartofdayET < 0) { - cumulus.LogMessage("ET not initialised"); + cumulus.LogMessage("ReadTodayFile: ET not initialised"); noET = true; } else { ET = AnnualETTotal - StartofdayET; - cumulus.LogMessage("ET today = " + ET.ToString(cumulus.ETFormat)); + cumulus.LogMessage("ReadTodayFile: ET today = " + ET.ToString(cumulus.ETFormat)); } ChillHours = ini.GetValue("Temp", "ChillHours", 0.0); @@ -765,6 +827,7 @@ public void ReadTodayFile() DominantWindBearingMinutes = ini.GetValue("Wind", "DominantWindBearingMinutes", 0); DominantWindBearingX = ini.GetValue("Wind", "DominantWindBearingX", 0.0); DominantWindBearingY = ini.GetValue("Wind", "DominantWindBearingY", 0.0); + // Temperature HiLoToday.LowTemp = ini.GetValue("Temp", "Low", 999.0); HiLoToday.LowTempTime = ini.GetValue("Temp", "LTime", metoTodayDate); @@ -780,16 +843,19 @@ public void ReadTodayFile() CoolingDegreeDays = ini.GetValue("Temp", "CoolingDegreeDays", 0.0); GrowingDegreeDaysThisYear1 = ini.GetValue("Temp", "GrowingDegreeDaysThisYear1", 0.0); GrowingDegreeDaysThisYear2 = ini.GetValue("Temp", "GrowingDegreeDaysThisYear2", 0.0); + // Temperature midnight rollover HiLoTodayMidnight.LowTemp = ini.GetValue("TempMidnight", "Low", 999.0); HiLoTodayMidnight.LowTempTime = ini.GetValue("TempMidnight", "LTime", metoTodayDate); HiLoTodayMidnight.HighTemp = ini.GetValue("TempMidnight", "High", -999.0); HiLoTodayMidnight.HighTempTime = ini.GetValue("TempMidnight", "HTime", metoTodayDate); - // PressureHighDewpoint + + // Pressure HiLoToday.LowPress = ini.GetValue("Pressure", "Low", 9999.0); HiLoToday.LowPressTime = ini.GetValue("Pressure", "LTime", metoTodayDate); HiLoToday.HighPress = ini.GetValue("Pressure", "High", 0.0); HiLoToday.HighPressTime = ini.GetValue("Pressure", "HTime", metoTodayDate); + // rain HiLoToday.HighRainRate = ini.GetValue("Rain", "High", 0.0); HiLoToday.HighRainRateTime = ini.GetValue("Rain", "HTime", metoTodayDate); @@ -797,43 +863,88 @@ public void ReadTodayFile() HiLoToday.HighHourlyRainTime = ini.GetValue("Rain", "HHourlyTime", metoTodayDate); HiLoToday.HighRain24h = ini.GetValue("Rain", "High24h", 0.0); HiLoToday.HighRain24hTime = ini.GetValue("Rain", "High24hTime", metoTodayDate); - raindaystart = ini.GetValue("Rain", "Start", -1.0); - cumulus.LogMessage($"ReadTodayfile: Rain day start = {raindaystart}"); RainYesterday = ini.GetValue("Rain", "Yesterday", 0.0); - if (raindaystart >= 0) + RainCounterDayStart = ini.GetValue("Rain", "Start", -1.0); + MidnightRainCount = ini.GetValue("Rain", "Midnight", -1.0); + RainCounter = ini.GetValue("Rain", "Last", -1.0); + + if (RainCounterDayStart == -1.0) { - cumulus.LogMessage("ReadTodayfile: set initialiseRainCounterOnFirstData false"); - initialiseRainCounterOnFirstData = false; + cumulus.LogMessage("ReadTodayfile: set initialiseRainDayStart true"); + initialiseRainDayStart = true; } + else + { + initialiseRainDayStart = false; + } + + if (RainCounter == -1.0) + { + cumulus.LogMessage("ReadTodayfile: set initialiseRainCounterOnFirstData true"); + initialiseRainCounter = true; + } + else + { + initialiseRainCounter = false; + } + + if (MidnightRainCount == -1.0) + { + if (cumulus.RolloverHour == 0 && !initialiseRainDayStart) + { + // midnight and rollover are the same + MidnightRainCount = RainCounterDayStart; + initialiseMidnightRain = false; + } + else + { + cumulus.LogMessage("ReadTodayfile: set initialiseMidnightRain true"); + initialiseMidnightRain = true; + } + } + else + { + initialiseMidnightRain = false; + } + + cumulus.LogMessage($"ReadTodayfile: Rain day start: {RainCounterDayStart:F4}, midnight counter: {MidnightRainCount:F4}, last counter: {RainCounter:F4}"); + // humidity HiLoToday.LowHumidity = ini.GetValue("Humidity", "Low", 100); HiLoToday.HighHumidity = ini.GetValue("Humidity", "High", 0); HiLoToday.LowHumidityTime = ini.GetValue("Humidity", "LTime", metoTodayDate); HiLoToday.HighHumidityTime = ini.GetValue("Humidity", "HTime", metoTodayDate); + // Solar SunshineHours = ini.GetValue("Solar", "SunshineHours", 0.0); SunshineToMidnight = ini.GetValue("Solar", "SunshineHoursToMidnight", 0.0); + // heat index HiLoToday.HighHeatIndex = ini.GetValue("HeatIndex", "High", -999.0); HiLoToday.HighHeatIndexTime = ini.GetValue("HeatIndex", "HTime", metoTodayDate); + // Apparent temp HiLoToday.HighAppTemp = ini.GetValue("AppTemp", "High", -999.0); HiLoToday.HighAppTempTime = ini.GetValue("AppTemp", "HTime", metoTodayDate); HiLoToday.LowAppTemp = ini.GetValue("AppTemp", "Low", 999.0); HiLoToday.LowAppTempTime = ini.GetValue("AppTemp", "LTime", metoTodayDate); + // wind chill HiLoToday.LowWindChill = ini.GetValue("WindChill", "Low", 999.0); HiLoToday.LowWindChillTime = ini.GetValue("WindChill", "LTime", metoTodayDate); + // Dew point HiLoToday.HighDewPoint = ini.GetValue("Dewpoint", "High", -999.0); HiLoToday.HighDewPointTime = ini.GetValue("Dewpoint", "HTime", metoTodayDate); HiLoToday.LowDewPoint = ini.GetValue("Dewpoint", "Low", 999.0); HiLoToday.LowDewPointTime = ini.GetValue("Dewpoint", "LTime", metoTodayDate); + // Feels like HiLoToday.HighFeelsLike = ini.GetValue("FeelsLike", "High", -999.0); HiLoToday.HighFeelsLikeTime = ini.GetValue("FeelsLike", "HTime", metoTodayDate); HiLoToday.LowFeelsLike = ini.GetValue("FeelsLike", "Low", 999.0); HiLoToday.LowFeelsLikeTime = ini.GetValue("FeelsLike", "LTime", metoTodayDate); + // Humidex HiLoToday.HighHumidex = ini.GetValue("Humidex", "High", -999.0); HiLoToday.HighHumidexTime = ini.GetValue("Humidex", "HTime", metoTodayDate); @@ -902,8 +1013,10 @@ public void WriteTodayFile(DateTime timestamp, bool Log) ini.SetValue("Rain", "HHourlyTime", HiLoToday.HighHourlyRainTime.ToString("HH:mm")); ini.SetValue("Rain", "High24h", HiLoToday.HighRain24h); ini.SetValue("Rain", "High24hTime", HiLoToday.HighRain24hTime.ToString("HH:mm")); - ini.SetValue("Rain", "Start", raindaystart); ini.SetValue("Rain", "Yesterday", RainYesterday); + ini.SetValue("Rain", "Start", RainCounterDayStart); + ini.SetValue("Rain", "Midnight", MidnightRainCount); + ini.SetValue("Rain", "Last", RainCounter); ini.SetValue("Rain", "LastTip", LastRainTip); ini.SetValue("Rain", "ConsecutiveRainDays", ConsecutiveRainDays); ini.SetValue("Rain", "ConsecutiveDryDays", ConsecutiveDryDays); @@ -970,16 +1083,15 @@ public void WriteTodayFile(DateTime timestamp, bool Log) if (Log) { - cumulus.LogMessage("Writing today.ini, LastUpdateTime = " + cumulus.LastUpdateTime + " raindaystart = " + raindaystart.ToString("F2") + " rain counter = " + - Raincounter.ToString("F2")); + cumulus.LogMessage("Writing today.ini, LastUpdateTime = " + cumulus.LastUpdateTime + " raindaystart = " + RainCounterDayStart.ToString("F2") + " rain counter = " + RainCounter.ToString("F2")); if (cumulus.FineOffsetStation) { - cumulus.LogMessage("Latest reading: " + LatestFOReading); + cumulus.LogMessage("WriteTodayFile: Latest FO reading: " + LatestFOReading); } else if (cumulus.StationType == StationTypes.Instromet) { - cumulus.LogMessage("Latest reading: " + cumulus.LatestImetReading); + cumulus.LogMessage("WriteTodayFile: Latest Instromet reading: " + cumulus.LatestImetReading); } } @@ -1342,7 +1454,7 @@ private string FormatDateTime(string fmt, DateTime timestamp) public double ChillHours { get; set; } - public double midnightraincount { get; set; } + public double MidnightRainCount { get; set; } public int MidnightRainResetDay { get; set; } @@ -1587,10 +1699,24 @@ public void SecondTimer(object sender, ElapsedEventArgs e) } } - // send current data to web-socket every 5 seconds, unless it has already been sent within the 10 seconds - if (LastDataReadTimestamp.AddSeconds(5) < timeNow && (int) timeNow.TimeOfDay.TotalMilliseconds % 10000 <= 500) + if (timeNow.Second != lastSecond) { - _ = sendWebSocketData(); + lastSecond = timeNow.Second; + + // send current data to web-socket every 5 seconds, unless it has already been sent within the 10 seconds + if (LastDataReadTimestamp.AddSeconds(5) < timeNow && (int) timeNow.TimeOfDay.TotalMilliseconds % 10000 <= 500) + { + _ = sendWebSocketData(); + } + + // lets spread some the processing over the minute, 12 seconds past the minute... + var millisecs = (int) timeNow.TimeOfDay.TotalMilliseconds % 60000; + if (millisecs >= 12000 && millisecs < 12500) + { + MinutePlus12Changed(timeNow); + } + + cumulus.MQTTSecondChanged(timeNow); } } @@ -1609,7 +1735,6 @@ internal async Task sendWebSocketData(bool wait = false) // Return control to the calling method immediately. await Task.Yield(); - // send current data to web-socket try { @@ -1707,6 +1832,14 @@ private void ClearAlarms() cumulus.FtpAlarm.ClearAlarm(); } + private void CheckUserAlarms() + { + foreach (var alarm in cumulus.UserAlarms) + { + alarm.CheckAlarm(); + } + } + private void MinuteChanged(DateTime now) { CheckForDataStopped(); @@ -1770,12 +1903,12 @@ private void MinuteChanged(DateTime now) DoTrendValues(now); DoPressTrend("Enable Cumulus pressure trend"); AddRecentDataWithAq(now, WindAverage, RecentMaxGust, WindLatest, Bearing, AvgBearing, OutdoorTemperature, WindChill, OutdoorDewpoint, HeatIndex, OutdoorHumidity, - Pressure, RainToday, SolarRad, UV, Raincounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); + Pressure, RainToday, SolarRad, UV, RainCounter, FeelsLike, Humidex, ApparentTemperature, IndoorTemperature, IndoorHumidity, CurrentSolarMax, RainRate); // calculate ET just before the hour so it is included in the correct day at roll over - only affects 9am met days really if (cumulus.StationOptions.CalculatedET && now.Minute == 59) { - CalculateEvaoptranspiration(now); + CalculateEvapotranspiration(now); } @@ -1918,18 +2051,18 @@ private void MinuteChanged(DateTime now) xapReport.Append("}\n"); xapReport.Append("weather.report\n{\n"); xapReport.Append($"UTC={timeUTC}\nDATE={dateISO}\n"); - xapReport.Append($"WindM={ConvertUserWindToMPH(WindAverage):F1}\n"); - xapReport.Append($"WindK={ConvertUserWindToKPH(WindAverage):F1}\n"); - xapReport.Append($"WindGustsM={ConvertUserWindToMPH(RecentMaxGust):F1}\n"); - xapReport.Append($"WindGustsK={ConvertUserWindToKPH(RecentMaxGust):F1}\n"); + xapReport.Append($"WindM={ConvertUnits.UserWindToMPH(WindAverage):F1}\n"); + xapReport.Append($"WindK={ConvertUnits.UserWindToKPH(WindAverage):F1}\n"); + xapReport.Append($"WindGustsM={ConvertUnits.UserWindToMPH(RecentMaxGust):F1}\n"); + xapReport.Append($"WindGustsK={ConvertUnits.UserWindToKPH(RecentMaxGust):F1}\n"); xapReport.Append($"WindDirD={Bearing}\n"); xapReport.Append($"WindDirC={AvgBearing}\n"); - xapReport.Append($"TempC={ConvertUserTempToC(OutdoorTemperature):F1}\n"); - xapReport.Append($"TempF={ConvertUserTempToF(OutdoorTemperature):F1}\n"); - xapReport.Append($"DewC={ConvertUserTempToC(OutdoorDewpoint):F1}\n"); - xapReport.Append($"DewF={ConvertUserTempToF(OutdoorDewpoint):F1}\n"); - xapReport.Append($"AirPressure={ConvertUserPressToMB(Pressure):F1}\n"); - xapReport.Append($"Rain={ConvertUserRainToMM(RainToday):F1}\n"); + xapReport.Append($"TempC={ConvertUnits.UserTempToC(OutdoorTemperature):F1}\n"); + xapReport.Append($"TempF={ConvertUnits.UserTempToF(OutdoorTemperature):F1}\n"); + xapReport.Append($"DewC={ConvertUnits.UserTempToC(OutdoorDewpoint):F1}\n"); + xapReport.Append($"DewF={ConvertUnits.UserTempToF(OutdoorDewpoint):F1}\n"); + xapReport.Append($"AirPressure={ConvertUnits.UserPressToMB(Pressure):F1}\n"); + xapReport.Append($"Rain={ConvertUnits.UserRainToMM(RainToday):F1}\n"); xapReport.Append('}'); data = Encoding.ASCII.GetBytes(xapReport.ToString()); @@ -1960,6 +2093,14 @@ private void MinuteChanged(DateTime now) cumulus.LogMessage("Checking for latest Cumulus MX version..."); cumulus.GetLatestVersion(); } + } + + private void MinutePlus12Changed(DateTime now) + { + if (!DataStopped) + { + CheckUserAlarms(); + } // If not on windows, check for CPU temp try @@ -1969,7 +2110,7 @@ private void MinuteChanged(DateTime now) var raw = File.ReadAllText(@"/sys/class/thermal/thermal_zone0/temp"); if (double.TryParse(raw, out var val)) { - cumulus.CPUtemp = ConvertTempCToUser(val / 1000); + cumulus.CPUtemp = ConvertUnits.TempCToUser(val / 1000); cumulus.LogDebugMessage($"Current CPU temp = {cumulus.CPUtemp.ToString(cumulus.TempFormat)}{cumulus.Units.TempText}"); } else @@ -2139,7 +2280,7 @@ internal void UpdateDatabase(DateTime timestamp, int interval, bool updateHighsA */ - public void CalculateEvaoptranspiration(DateTime date) + public void CalculateEvapotranspiration(DateTime date) { cumulus.LogDebugMessage("Calculating ET from data"); @@ -2150,16 +2291,16 @@ public void CalculateEvaoptranspiration(DateTime date) // finally calculate the ETo var newET = MeteoLib.Evapotranspiration( - ConvertUserTempToC(result[0].avgTemp), + ConvertUnits.UserTempToC(result[0].avgTemp), result[0].avgHum, result[0].avgSol, result[0].avgSolMax, - ConvertUserWindToMS(result[0].avgWind), - ConvertUserPressureToHPa(result[0].avgPress) / 10 + ConvertUnits.UserWindToMS(result[0].avgWind), + ConvertUnits.UserPressureToHPa(result[0].avgPress) / 10 ); // convert to user units - newET = ConvertRainMMToUser(newET); + newET = ConvertUnits.RainMMToUser(newET); cumulus.LogDebugMessage($"Calculated ET for the last hour = {newET:F3}"); // DoET expects the running annual total to be sent @@ -4843,20 +4984,20 @@ public string CreateWxnowFileString() var timestamp = DateTime.Now.ToString(@"MMM dd yyyy HH\:mm"); - int mphwind = Convert.ToInt32(ConvertUserWindToMPH(WindAverage)); - int mphgust = Convert.ToInt32(ConvertUserWindToMPH(RecentMaxGust)); + int mphwind = Convert.ToInt32(ConvertUnits.UserWindToMPH(WindAverage)); + int mphgust = Convert.ToInt32(ConvertUnits.UserWindToMPH(RecentMaxGust)); // ftemp = trunc(TempF(OutsideTemp)); string ftempstr = APRStemp(OutdoorTemperature); - int in100rainlasthour = Convert.ToInt32(ConvertUserRainToIn(RainLastHour) * 100); - int in100rainlast24hours = Convert.ToInt32(ConvertUserRainToIn(RainLast24Hour) * 100); + int in100rainlasthour = Convert.ToInt32(ConvertUnits.UserRainToIN(RainLastHour) * 100); + int in100rainlast24hours = Convert.ToInt32(ConvertUnits.UserRainToIN(RainLast24Hour) * 100); int in100raintoday; if (cumulus.RolloverHour == 0) // use today's rain for safety - in100raintoday = Convert.ToInt32(ConvertUserRainToIn(RainToday) * 100); + in100raintoday = Convert.ToInt32(ConvertUnits.UserRainToIN(RainToday) * 100); else // 0900 day, use midnight calculation - in100raintoday = Convert.ToInt32(ConvertUserRainToIn(RainSinceMidnight) * 100); - int mb10press = Convert.ToInt32(ConvertUserPressToMB(AltimeterPressure) * 10); + in100raintoday = Convert.ToInt32(ConvertUnits.UserRainToIN(RainSinceMidnight) * 100); + int mb10press = Convert.ToInt32(ConvertUnits.UserPressToMB(AltimeterPressure) * 10); // For 100% humidity, send zero. For zero humidity, send 1 int hum; if (OutdoorHumidity == 0) @@ -4925,52 +5066,6 @@ private string APRStemp(double temp) } } - private double ConvertUserRainToIn(double value) - { - if (cumulus.Units.Rain == 1) - { - return value; - } - else - { - return value / 25.4; - } - } - - public double ConvertUserWindToMPH(double value) - { - switch (cumulus.Units.Wind) - { - case 0: - return value * 2.23693629; - case 1: - return value; - case 2: - return value * 0.621371; - case 3: - return value * 1.15077945; - default: - return 0; - } - } - - public double ConvertUserWindToKnots(double value) - { - switch (cumulus.Units.Wind) - { - case 0: - return value * 1.943844; - case 1: - return value * 0.8689758; - case 2: - return value * 0.5399565; - case 3: - return value; - default: - return 0; - } - } - public void ResetSunshineHours(DateTime logdate) // called at midnight irrespective of roll-over time { @@ -5037,15 +5132,15 @@ public void ResetMidnightRain(DateTime timestamp) if (mrrday != MidnightRainResetDay) { - midnightraincount = Raincounter; + MidnightRainCount = RainCounter; RainSinceMidnight = 0; MidnightRainResetDay = mrrday; - cumulus.LogMessage("Midnight rain reset, count = " + Raincounter + " time = " + timestamp.ToShortTimeString()); + cumulus.LogMessage("Midnight rain reset, count = " + RainCounter + " time = " + timestamp.ToShortTimeString()); if ((mrrday == 1) && (mrrmonth == 1) && (cumulus.StationType == StationTypes.VantagePro)) { // special case: rain counter is about to be reset cumulus.LogMessage("Special case, Davis station on 1st Jan. Set midnight rain count to zero"); - midnightraincount = 0; + MidnightRainCount = 0; } } } @@ -5063,7 +5158,18 @@ public void DoIndoorHumidity(int hum) return; } - IndoorHumidity = (int) Math.Round((hum * cumulus.Calib.InHum.Mult) + cumulus.Calib.InHum.Offset); + previousInHum = hum; + IndoorHumidity = (int) cumulus.Calib.InHum.Calibrate(hum); + + if (IndoorHumidity < 0) + { + IndoorHumidity = 0; + } + if (IndoorHumidity > 100) + { + IndoorHumidity = 100; + } + HaveReadData = true; } @@ -5080,6 +5186,7 @@ public void DoIndoorTemp(double temp) return; } + previousInTemp = temp; IndoorTemperature = cumulus.Calib.InTemp.Calibrate(temp); HaveReadData = true; } @@ -5104,12 +5211,9 @@ public void DoOutdoorHumidity(int humpar, DateTime timestamp) } else { - OutdoorHumidity = humpar; + OutdoorHumidity = (int) cumulus.Calib.Hum.Calibrate(humpar); } - // apply offset and multipliers and round. This is different to C1, which truncates. I'm not sure why C1 does that - OutdoorHumidity = (int) Math.Round((OutdoorHumidity * OutdoorHumidity * cumulus.Calib.Hum.Mult2) + (OutdoorHumidity * cumulus.Calib.Hum.Mult) + cumulus.Calib.Hum.Offset); - if (OutdoorHumidity < 0) { OutdoorHumidity = 0; @@ -5171,26 +5275,23 @@ public void DoOutdoorHumidity(int humpar, DateTime timestamp) public void DoOutdoorTemp(double temp, DateTime timestamp) { - // Spike removal is in Celsius - var tempC = ConvertUserTempToC(temp); - if (((Math.Abs(tempC - previousTemp) > cumulus.Spike.TempDiff) && (previousTemp != 999)) || - tempC >= cumulus.Limit.TempHigh || tempC <= cumulus.Limit.TempLow) + // Spike removal + if (((Math.Abs(temp - previousTemp) > cumulus.Spike.TempDiff) && (previousTemp != 999)) || + temp >= cumulus.Limit.TempHigh || temp <= cumulus.Limit.TempLow) { lastSpikeRemoval = DateTime.Now; - cumulus.SpikeAlarm.LastMessage = $"Temp difference greater than spike value - NewVal={tempC.ToString(cumulus.TempFormat)} OldVal={previousTemp.ToString(cumulus.TempFormat)}"; + cumulus.SpikeAlarm.LastMessage = $"Temp difference greater than spike value - NewVal={temp.ToString(cumulus.TempFormat)} OldVal={previousTemp.ToString(cumulus.TempFormat)}"; cumulus.SpikeAlarm.Triggered = true; cumulus.LogSpikeRemoval("Temp difference greater than specified; reading ignored"); - cumulus.LogSpikeRemoval($"NewVal={tempC.ToString(cumulus.TempFormat)} OldVal={previousTemp.ToString(cumulus.TempFormat)} SpikeTempDiff={cumulus.Spike.TempDiff.ToString(cumulus.TempFormat)} HighLimit={cumulus.Limit.TempHigh.ToString(cumulus.TempFormat)} LowLimit={cumulus.Limit.TempLow.ToString(cumulus.TempFormat)}"); + cumulus.LogSpikeRemoval($"NewVal={temp.ToString(cumulus.TempFormat)} OldVal={previousTemp.ToString(cumulus.TempFormat)} SpikeTempDiff={cumulus.Spike.TempDiff.ToString(cumulus.TempFormat)} HighLimit={cumulus.Limit.TempHigh.ToString(cumulus.TempFormat)} LowLimit={cumulus.Limit.TempLow.ToString(cumulus.TempFormat)}"); return; } - previousTemp = tempC; + previousTemp = temp; // UpdateStatusPanel; // update global temp OutdoorTemperature = cumulus.Calib.Temp.Calibrate(temp); - double tempinC = ConvertUserTempToC(OutdoorTemperature); - first_temp = false; // Does this reading set any records or trigger any alarms? @@ -5269,7 +5370,8 @@ public void DoOutdoorTemp(double temp, DateTime timestamp) if ((cumulus.StationOptions.CalculatedDP || cumulus.DavisStation) && (OutdoorHumidity != 0) && (!cumulus.FineOffsetStation)) { // Calculate DewPoint. - OutdoorDewpoint = ConvertTempCToUser(MeteoLib.DewPoint(tempinC, OutdoorHumidity)); + double tempinC = ConvertUnits.UserTempToC(OutdoorTemperature); + OutdoorDewpoint = ConvertUnits.TempCToUser(MeteoLib.DewPoint(tempinC, OutdoorHumidity)); CheckForDewpointHighLow(timestamp); } @@ -5281,15 +5383,15 @@ public void DoOutdoorTemp(double temp, DateTime timestamp) public void DoCloudBaseHeatIndex(DateTime timestamp) { - var tempinF = ConvertUserTempToF(OutdoorTemperature); - var tempinC = ConvertUserTempToC(OutdoorTemperature); + var tempinF = ConvertUnits.UserTempToF(OutdoorTemperature); + var tempinC = ConvertUnits.UserTempToC(OutdoorTemperature); // Calculate cloud base - CloudBase = (int) Math.Floor((tempinF - ConvertUserTempToF(OutdoorDewpoint)) / 4.4 * 1000 / (cumulus.CloudBaseInFeet ? 1 : 3.2808399)); + CloudBase = (int) Math.Floor((tempinF - ConvertUnits.UserTempToF(OutdoorDewpoint)) / 4.4 * 1000 / (cumulus.CloudBaseInFeet ? 1 : 3.2808399)); if (CloudBase < 0) CloudBase = 0; - HeatIndex = ConvertTempCToUser(MeteoLib.HeatIndex(tempinC, OutdoorHumidity)); + HeatIndex = ConvertUnits.TempCToUser(MeteoLib.HeatIndex(tempinC, OutdoorHumidity)); if (HeatIndex > HiLoToday.HighHeatIndex) { @@ -5321,7 +5423,7 @@ public void DoCloudBaseHeatIndex(DateTime timestamp) // Find estimated wet bulb temp. First time this is called, required variables may not have been set up yet try { - WetBulb = ConvertTempCToUser(MeteoLib.CalculateWetBulbC(tempinC, ConvertUserTempToC(OutdoorDewpoint), ConvertUserPressToMB(Pressure))); + WetBulb = ConvertUnits.TempCToUser(MeteoLib.CalculateWetBulbC(tempinC, ConvertUnits.UserTempToC(OutdoorDewpoint), ConvertUnits.UserPressToMB(Pressure))); } catch { @@ -5338,13 +5440,13 @@ public void DoApparentTemp(DateTime timestamp) //if (TempReadyToPlot && WindReadyToPlot) //{ //ApparentTemperature = - //ConvertTempCToUser(ConvertUserTempToC(OutdoorTemperature) + (0.33 * MeteoLib.ActualVapourPressure(ConvertUserTempToC(OutdoorTemperature), OutdoorHumidity)) - - // (0.7 * ConvertUserWindToMS(WindAverage)) - 4); - ApparentTemperature = ConvertTempCToUser(MeteoLib.ApparentTemperature(ConvertUserTempToC(OutdoorTemperature), ConvertUserWindToMS(WindAverage), OutdoorHumidity)); + //ConvertUnits.TempCToUser(ConvertUnits.UserTempToC(OutdoorTemperature) + (0.33 * MeteoLib.ActualVapourPressure(ConvertUnits.UserTempToC(OutdoorTemperature), OutdoorHumidity)) - + // (0.7 * ConvertUnits.UserWindToMS(WindAverage)) - 4); + ApparentTemperature = ConvertUnits.TempCToUser(MeteoLib.ApparentTemperature(ConvertUnits.UserTempToC(OutdoorTemperature), ConvertUnits.UserWindToMS(WindAverage), OutdoorHumidity)); // we will tag on the THW Index here - THWIndex = ConvertTempCToUser(MeteoLib.THWIndex(ConvertUserTempToC(OutdoorTemperature), OutdoorHumidity, ConvertUserWindToKPH(WindAverage))); + THWIndex = ConvertUnits.TempCToUser(MeteoLib.THWIndex(ConvertUnits.UserTempToC(OutdoorTemperature), OutdoorHumidity, ConvertUnits.UserWindToKPH(WindAverage))); if (ApparentTemperature > HiLoToday.HighAppTemp) { @@ -5408,12 +5510,12 @@ public void DoWindChill(double chillpar, DateTime timestamp) // don"t try to calculate wind chill if we haven"t yet had wind and temp readings if (TempReadyToPlot && WindReadyToPlot) { - double TempinC = ConvertUserTempToC(OutdoorTemperature); - double windinKPH = ConvertUserWindToKPH(WindAverage); + double TempinC = ConvertUnits.UserTempToC(OutdoorTemperature); + double windinKPH = ConvertUnits.UserWindToKPH(WindAverage); // no wind chill below 1.5 m/s = 5.4 km if (windinKPH >= 5.4) { - WindChill = ConvertTempCToUser(MeteoLib.WindChill(TempinC, windinKPH)); + WindChill = ConvertUnits.TempCToUser(MeteoLib.WindChill(TempinC, windinKPH)); } else { @@ -5467,7 +5569,7 @@ public void DoWindChill(double chillpar, DateTime timestamp) public void DoFeelsLike(DateTime timestamp) { - FeelsLike = ConvertTempCToUser(MeteoLib.FeelsLike(ConvertUserTempToC(OutdoorTemperature), ConvertUserWindToKPH(WindAverage), OutdoorHumidity)); + FeelsLike = ConvertUnits.TempCToUser(MeteoLib.FeelsLike(ConvertUnits.UserTempToC(OutdoorTemperature), ConvertUnits.UserWindToKPH(WindAverage), OutdoorHumidity)); if (FeelsLike > HiLoToday.HighFeelsLike) { @@ -5523,7 +5625,7 @@ public void DoFeelsLike(DateTime timestamp) public void DoHumidex(DateTime timestamp) { - Humidex = MeteoLib.Humidex(ConvertUserTempToC(OutdoorTemperature), OutdoorHumidity); + Humidex = MeteoLib.Humidex(ConvertUnits.UserTempToC(OutdoorTemperature), OutdoorHumidity); if (Humidex > HiLoToday.HighHumidex) { @@ -5630,20 +5732,19 @@ public void CheckForDewpointHighLow(DateTime timestamp) public void DoPressure(double sl, DateTime timestamp) { - // Spike removal is in mb/hPa - var pressMB = ConvertUserPressToMB(sl); - if (((Math.Abs(pressMB - previousPress) > cumulus.Spike.PressDiff) && (previousPress != 9999)) || - pressMB >= cumulus.Limit.PressHigh || pressMB <= cumulus.Limit.PressLow) + // Spike removal + if (((Math.Abs(sl - previousPress) > cumulus.Spike.PressDiff) && (previousPress != 9999)) || + sl >= cumulus.Limit.PressHigh || sl <= cumulus.Limit.PressLow) { cumulus.LogSpikeRemoval("Pressure difference greater than specified; reading ignored"); - cumulus.LogSpikeRemoval($"NewVal={pressMB:F1} OldVal={previousPress:F1} SpikePressDiff={cumulus.Spike.PressDiff:F1} HighLimit={cumulus.Limit.PressHigh:F1} LowLimit={cumulus.Limit.PressLow:F1}"); + cumulus.LogSpikeRemoval($"NewVal={sl:F1} OldVal={previousPress:F1} SpikePressDiff={cumulus.Spike.PressDiff:F1} HighLimit={cumulus.Limit.PressHigh:F1} LowLimit={cumulus.Limit.PressLow:F1}"); lastSpikeRemoval = DateTime.Now; - cumulus.SpikeAlarm.LastMessage = $"Pressure difference greater than spike value - NewVal={pressMB:F1} OldVal={previousPress:F1}"; + cumulus.SpikeAlarm.LastMessage = $"Pressure difference greater than spike value - NewVal={sl:F1} OldVal={previousPress:F1}"; cumulus.SpikeAlarm.Triggered = true; return; } - previousPress = pressMB; + previousPress = sl; Pressure = cumulus.Calib.Press.Calibrate(sl); if (cumulus.Manufacturer == cumulus.DAVIS) @@ -5658,7 +5759,7 @@ public void DoPressure(double sl, DateTime timestamp) { if (cumulus.Manufacturer == cumulus.OREGONUSB) { - AltimeterPressure = ConvertPressMBToUser(StationToAltimeter(ConvertUserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); + AltimeterPressure = ConvertUnits.PressMBToUser(StationToAltimeter(ConvertUnits.UserPressureToHPa(StationPressure), AltitudeM(cumulus.Altitude))); } else { @@ -5749,14 +5850,13 @@ public void DoRain(double total, double rate, DateTime timestamp) //cumulus.LogDebugMessage($"DoRain: counter={total}, rate={rate}; RainToday={RainToday}, StartOfDay={raindaystart}"); - // Spike removal is in mm - var rainRateMM = ConvertUserRainToMM(rate); - if (rainRateMM > cumulus.Spike.MaxRainRate) + // Spike removal + if (rate > cumulus.Spike.MaxRainRate) { cumulus.LogSpikeRemoval("Rain rate greater than specified; reading ignored"); - cumulus.LogSpikeRemoval($"Rate value = {rainRateMM:F2} SpikeMaxRainRate = {cumulus.Spike.MaxRainRate:F2}"); - lastSpikeRemoval = DateTime.Now; - cumulus.SpikeAlarm.LastMessage = $"Rain rate greater than spike value - value = {rainRateMM:F2}mm/hr"; + cumulus.LogSpikeRemoval($"Rate value = {rate:F2} SpikeMaxRainRate = {cumulus.Spike.MaxRainRate:F2}"); + lastSpikeRemoval = timestamp; + cumulus.SpikeAlarm.LastMessage = $"Rain rate greater than spike value - value = {rate:F2}mm/hr"; cumulus.SpikeAlarm.Triggered = true; return; } @@ -5769,10 +5869,10 @@ public void DoRain(double total, double rate, DateTime timestamp) return; } - var previoustotal = Raincounter; + var previoustotal = RainCounter; // This is just to stop rounding errors triggering phantom rain days - double raintipthreshold = cumulus.Units.Rain == 0 ? 0.009 : 0.0003; + //double raintipthreshold = cumulus.Units.Rain == 0 ? 0.009 : 0.0003; /* if (cumulus.Manufacturer == cumulus.DAVIS) // Davis can have either 0.2mm or 0.01in buckets, and the user could select to measure in mm or inches! @@ -5815,16 +5915,24 @@ public void DoRain(double total, double rate, DateTime timestamp) } */ - Raincounter = total; + RainCounter = total; - //first_rain = false; - if (initialiseRainCounterOnFirstData) + if (initialiseRainDayStart || initialiseMidnightRain) { - raindaystart = Raincounter; - midnightraincount = Raincounter; - cumulus.LogMessage(" First rain data, raindaystart = " + raindaystart); + initialiseRainDayStart = false; + initialiseMidnightRain = false; + + if (initialiseRainDayStart) + { + RainCounterDayStart = RainCounter; + cumulus.LogMessage(" First rain data, raindaystart = " + RainCounterDayStart); + } + + if (initialiseMidnightRain) + { + MidnightRainCount = RainCounter; + } - initialiseRainCounterOnFirstData = false; WriteTodayFile(timestamp, false); HaveReadData = true; return; @@ -5832,36 +5940,37 @@ public void DoRain(double total, double rate, DateTime timestamp) // Has the rain total in the station been reset? // raindaystart greater than current total, allow for rounding - if (raindaystart - Raincounter > raintipthreshold) + if (Math.Round(RainCounterDayStart, cumulus.RainDPlaces) - Math.Round(RainCounter, cumulus.RainDPlaces) > 0) { if (FirstChanceRainReset) // second consecutive reading with reset value { - cumulus.LogWarningMessage(" ****Rain counter reset confirmed: raindaystart = " + raindaystart + ", Raincounter = " + Raincounter); + cumulus.LogWarningMessage(" ****Rain counter reset confirmed: raindaystart = " + RainCounterDayStart + ", Raincounter = " + RainCounter); // set the start of day figure so it reflects the rain // so far today - raindaystart = Raincounter - (RainToday / cumulus.Calib.Rain.Mult); - cumulus.LogMessage("Setting raindaystart to " + raindaystart); + RainCounterDayStart = RainCounter - (RainToday / cumulus.Calib.Rain.Mult); + cumulus.LogMessage("Setting raindaystart to " + RainCounterDayStart); - midnightraincount = Raincounter; + MidnightRainCount = RainCounter; + previoustotal = total; // update any data in the recent data db - var counterChange = Raincounter - prevraincounter; + var counterChange = RainCounter - prevraincounter; RecentDataDb.Execute("update RecentData set raincounter=raincounter+?", counterChange); FirstChanceRainReset = false; } else { - cumulus.LogMessage(" ****Rain reset? First chance: raindaystart = " + raindaystart + ", Raincounter = " + Raincounter); + cumulus.LogMessage(" ****Rain reset? First chance: raindaystart = " + RainCounterDayStart + ", Raincounter = " + RainCounter); // reset the counter to ignore this reading - Raincounter = previoustotal; - cumulus.LogMessage("Leaving counter at " + Raincounter); + RainCounter = previoustotal; + cumulus.LogMessage("Leaving counter at " + RainCounter); // stash the previous rain counter - prevraincounter = Raincounter; + prevraincounter = RainCounter; FirstChanceRainReset = true; } @@ -5915,7 +6024,7 @@ public void DoRain(double total, double rate, DateTime timestamp) if (!FirstChanceRainReset) { // Has a tip occurred? - if (total - previoustotal > raintipthreshold) + if (Math.Round(total, cumulus.RainDPlaces) - Math.Round(previoustotal, cumulus.RainDPlaces) > 0) { // rain has occurred LastRainTip = timestamp.ToString("yyyy-MM-dd HH:mm"); @@ -5933,14 +6042,11 @@ public void DoRain(double total, double rate, DateTime timestamp) } // Calculate today"s rainfall - RainToday = Raincounter - raindaystart; + RainToday = (RainCounter - RainCounterDayStart) * cumulus.Calib.Rain.Mult; //cumulus.LogDebugMessage("Uncalibrated RainToday = " + RainToday); - // scale for calibration - RainToday *= cumulus.Calib.Rain.Mult; - // Calculate rain since midnight for Wunderground etc - double trendval = Raincounter - midnightraincount; + double trendval = RainCounter - MidnightRainCount; // Round value as some values may have been read from log file and already rounded trendval = Math.Round(trendval, cumulus.RainDPlaces); @@ -5955,13 +6061,13 @@ public void DoRain(double total, double rate, DateTime timestamp) } // rain this month so far - RainMonth = rainthismonth + RainToday; + RainMonth = RainThisMonth + RainToday; // get correct date for rain records var offsetdate = timestamp.AddHours(cumulus.GetHourInc()); // rain this year so far - RainYear = rainthisyear + RainToday; + RainYear = RainThisYear + RainToday; if (RainToday > AllTime.DailyRain.Val) SetAlltime(AllTime.DailyRain, RainToday, offsetdate); @@ -6009,11 +6115,11 @@ public void DoOutdoorDewpoint(double dp, DateTime timestamp) if (cumulus.StationOptions.CalculatedDP || dp < -500) { - dp = ConvertTempCToUser(MeteoLib.DewPoint(ConvertUserTempToC(OutdoorTemperature), OutdoorHumidity)); + dp = ConvertUnits.TempCToUser(MeteoLib.DewPoint(ConvertUnits.UserTempToC(OutdoorTemperature), OutdoorHumidity)); } - if (ConvertUserTempToC(dp) <= cumulus.Limit.DewHigh) + if (ConvertUnits.UserTempToC(dp) <= cumulus.Limit.DewHigh) { OutdoorDewpoint = dp; CheckForDewpointHighLow(timestamp); @@ -6113,7 +6219,7 @@ public void DoForecast(string forecast, bool hourly) hp = cumulus.FChighpress / 0.0295333727; } - CumulusForecast = BetelCast(ConvertUserPressureToHPa(Pressure), DateTime.Now.Month, windDir, bartrend, cumulus.Latitude > 0, hp, lp); + CumulusForecast = BetelCast(ConvertUnits.UserPressureToHPa(Pressure), DateTime.Now.Month, windDir, bartrend, cumulus.Latitude > 0, hp, lp); if (cumulus.UseCumulusForecast) { @@ -6151,18 +6257,6 @@ public double AltitudeM(double altitude) } } - /// - /// Convert pressure from user units to hPa - /// - /// - /// - public double ConvertUserPressureToHPa(double value) - { - if (cumulus.Units.Press == 2) - return value / 0.0295333727; - else - return value; - } public double StationToAltimeter(double pressureHPa, double elevationM) { @@ -6190,26 +6284,29 @@ public void DoWind(double gustpar, int bearingpar, double speedpar, DateTime tim { cumulus.LogDebugMessage($"DoWind: latest={gustpar:F1}, speed={speedpar:F1} - Current: gust={RecentMaxGust:F1}, speed={WindAverage:F1}"); // if we have a spike in wind speed or gust, ignore the reading - // Spike removal is in m/s - var windGustMS = ConvertUserWindToMS(gustpar); - var windAvgMS = speedpar == -1 ? previousWind : ConvertUserWindToMS(speedpar); - - if (((Math.Abs(windGustMS - previousGust) > cumulus.Spike.GustDiff) && (previousGust != 999)) || - ((Math.Abs(windAvgMS - previousWind) > cumulus.Spike.WindDiff) && (previousWind != 999)) || - windGustMS >= cumulus.Limit.WindHigh - ) - { - cumulus.LogSpikeRemoval("Wind or gust difference greater than specified; reading ignored"); - cumulus.LogSpikeRemoval($"Gust: NewVal={windGustMS:F1} OldVal={previousGust:F1} SpikeGustDiff={cumulus.Spike.GustDiff:F1} HighLimit={cumulus.Limit.WindHigh:F1}"); - cumulus.LogSpikeRemoval($"Wind: NewVal={windAvgMS:F1} OldVal={previousWind:F1} SpikeWindDiff={cumulus.Spike.WindDiff:F1}"); - lastSpikeRemoval = DateTime.Now; - cumulus.SpikeAlarm.LastMessage = $"Wind or gust difference greater than spike/limit value - Gust: NewVal={windGustMS:F1}m/s OldVal={previousGust:F1}m/s - Wind: NewVal={windAvgMS:F1}m/s OldVal={previousWind:F1}m/s"; + // Spike removal + if (previousGust != 999 && (Math.Abs(gustpar - previousGust) > cumulus.Spike.GustDiff || gustpar >= cumulus.Limit.WindHigh)) + { + cumulus.LogSpikeRemoval("Gust difference greater than specified; reading ignored"); + cumulus.LogSpikeRemoval($"Gust: NewVal={gustpar:F1} OldVal={previousGust:F1} SpikeGustDiff={cumulus.Spike.GustDiff:F1} HighLimit={cumulus.Limit.WindHigh:F1}"); + lastSpikeRemoval = timestamp; + cumulus.SpikeAlarm.LastMessage = $"Wind or gust difference greater than spike/limit value - Gust: NewVal={gustpar:F1}m/s OldVal={previousGust:F1}m/s"; + cumulus.SpikeAlarm.Triggered = true; + return; + } + + if (previousWind != 999 && (Math.Abs(speedpar - previousWind) > cumulus.Spike.WindDiff || speedpar >= cumulus.Limit.WindHigh)) + { + cumulus.LogSpikeRemoval("Wind difference greater than specified; reading ignored"); + cumulus.LogSpikeRemoval($"Wind: NewVal={speedpar:F1} OldVal={previousWind:F1} SpikeWindDiff={cumulus.Spike.WindDiff:F1} HighLimit={cumulus.Limit.WindHigh:F1}"); + lastSpikeRemoval = timestamp; + cumulus.SpikeAlarm.LastMessage = $"Wind or gust difference greater than spike/limit value - Wind: NewVal={speedpar:F1}m/s OldVal={previousWind:F1}m/s"; cumulus.SpikeAlarm.Triggered = true; return; } - previousGust = windGustMS; - previousWind = windAvgMS; + previousGust = gustpar; + previousWind = speedpar; calibratedgust = cumulus.Calib.WindGust.Calibrate(gustpar); var uncalibratedspeed = speedpar < 0 ? WindAverageUncalibrated : speedpar; @@ -6575,11 +6672,11 @@ protected void DoSunHours(double hrs) protected void DoWetBulb(double temp, DateTime timestamp) // Supplied in CELSIUS { - WetBulb = ConvertTempCToUser(temp); + WetBulb = ConvertUnits.TempCToUser(temp); WetBulb = cumulus.Calib.WetBulb.Calibrate(WetBulb); // calculate RH - double TempDry = ConvertUserTempToC(OutdoorTemperature); + double TempDry = ConvertUnits.UserTempToC(OutdoorTemperature); double Es = MeteoLib.SaturationVapourPressure1980(TempDry); double Ew = MeteoLib.SaturationVapourPressure1980(temp); double E = Ew - (0.00066 * (1 + 0.00115 * temp) * (TempDry - temp) * 1013); @@ -6589,7 +6686,7 @@ protected void DoWetBulb(double temp, DateTime timestamp) // Supplied in CELSIUS // Calculate DewPoint // dewpoint = TempinC + ((0.13 * TempinC) + 13.6) * Ln(humidity / 100); - OutdoorDewpoint = ConvertTempCToUser(MeteoLib.DewPoint(TempDry, hum)); + OutdoorDewpoint = ConvertUnits.TempCToUser(MeteoLib.DewPoint(TempDry, hum)); CheckForDewpointHighLow(timestamp); } @@ -6725,10 +6822,12 @@ private int getShortestAngle(int bearing1, int bearing2) //private bool first_rain = true; private bool FirstChanceRainReset = false; - public bool initialiseRainCounterOnFirstData = true; + private bool initialiseRainDayStart = true; + private bool initialiseMidnightRain = true; + private bool initialiseRainCounter = true; //private bool RainReadyToPlot = false; - private double rainthismonth = 0; - private double rainthisyear = 0; + private double RainThisMonth = 0; + private double RainThisYear = 0; //private bool WindChillReadyToPlot = false; public bool noET = false; private int DayResetDay = 0; @@ -6748,6 +6847,7 @@ private int getShortestAngle(int bearing1, int bearing2) public string DavisFirmwareVersion = "???"; public string GW1000FirmwareVersion = "???"; public string EcowittCameraUrl = string.Empty; + public string EcowittVideoUrl = string.Empty; public static Dictionary SensorReception { get; set; } @@ -6951,11 +7051,11 @@ public void DayReset(DateTime timestamp) // First save today"s extremes DoDayfile(timestamp); - cumulus.LogMessage("Raincounter = " + Raincounter + " Raindaystart = " + raindaystart); + cumulus.LogMessage("Raincounter = " + RainCounter + " Raindaystart = " + RainCounterDayStart); // Calculate yesterday"s rain, allowing for the multiplier - // raintotal && raindaystart are not calibrated - RainYesterday = (Raincounter - raindaystart) * cumulus.Calib.Rain.Mult; + RainYesterday = (RainCounter - RainCounterDayStart) * cumulus.Calib.Rain.Mult; cumulus.LogMessage("Rainyesterday (calibrated) set to " + RainYesterday); //AddRecentDailyData(timestamp.AddDays(-1), RainYesterday, (cumulus.RolloverHour == 0 ? SunshineHours : SunshineToMidnight), HiLoToday.LowTemp, HiLoToday.HighTemp, YestAvgTemp); @@ -7226,7 +7326,7 @@ public void DayReset(DateTime timestamp) CopyMonthIniFile(timestamp.AddDays(-1)); - rainthismonth = 0; + RainThisMonth = 0; ThisMonth.HighGust.Val = calibratedgust; ThisMonth.HighWind.Val = WindAverage; @@ -7288,7 +7388,7 @@ public void DayReset(DateTime timestamp) ThisMonth.HighDailyTempRange.Ts = timestamp; } else - rainthismonth += RainYesterday; + RainThisMonth += RainYesterday; if ((day == 1) && (month == 1)) { @@ -7371,11 +7471,11 @@ public void DayReset(DateTime timestamp) { // new year starting cumulus.LogMessage(" New rain season starting"); - rainthisyear = 0; + RainThisYear = 0; } else { - rainthisyear += RainYesterday; + RainThisYear += RainYesterday; } if ((day == 1) && (month == cumulus.ChillHourSeasonStart)) @@ -7392,16 +7492,16 @@ public void DayReset(DateTime timestamp) GrowingDegreeDaysThisYear2 = 0; } - GrowingDegreeDaysThisYear1 += MeteoLib.GrowingDegreeDays(ConvertUserTempToC(HiLoToday.HighTemp), ConvertUserTempToC(HiLoToday.LowTemp), ConvertUserTempToC(cumulus.GrowingBase1), cumulus.GrowingCap30C); - GrowingDegreeDaysThisYear2 += MeteoLib.GrowingDegreeDays(ConvertUserTempToC(HiLoToday.HighTemp), ConvertUserTempToC(HiLoToday.LowTemp), ConvertUserTempToC(cumulus.GrowingBase2), cumulus.GrowingCap30C); + GrowingDegreeDaysThisYear1 += MeteoLib.GrowingDegreeDays(ConvertUnits.UserTempToC(HiLoToday.HighTemp), ConvertUnits.UserTempToC(HiLoToday.LowTemp), ConvertUnits.UserTempToC(cumulus.GrowingBase1), cumulus.GrowingCap30C); + GrowingDegreeDaysThisYear2 += MeteoLib.GrowingDegreeDays(ConvertUnits.UserTempToC(HiLoToday.HighTemp), ConvertUnits.UserTempToC(HiLoToday.LowTemp), ConvertUnits.UserTempToC(cumulus.GrowingBase2), cumulus.GrowingCap30C); // Now reset all values to the current or default ones // We may be doing a roll-over from the first logger entry, // && as we do the roll-over before processing the entry, the // current items may not be set up. - raindaystart = Raincounter; - cumulus.LogMessage("Raindaystart set to " + raindaystart); + RainCounterDayStart = RainCounter; + cumulus.LogMessage("Raindaystart set to " + RainCounterDayStart); RainToday = 0; @@ -8021,314 +8121,6 @@ protected int BCDchartoint(int c) return ((c / 16) * 10) + (c % 16); } - /// - /// Convert temp supplied in C to units in use - /// - /// Temp in C - /// Temp in configured units - public double ConvertTempCToUser(double value) - { - if (cumulus.Units.Temp == 1) - { - return MeteoLib.CToF(value); - } - else - { - // C - return value; - } - } - - /// - /// Convert temp supplied in F to units in use - /// - /// Temp in F - /// Temp in configured units - public double ConvertTempFToUser(double value) - { - if (cumulus.Units.Temp == 0) - { - return MeteoLib.FtoC(value); - } - else - { - // F - return value; - } - } - - /// - /// Convert temp supplied in user units to C - /// - /// Temp in configured units - /// Temp in C - public double ConvertUserTempToC(double value) - { - if (cumulus.Units.Temp == 1) - { - return MeteoLib.FtoC(value); - } - else - { - // C - return value; - } - } - - /// - /// Convert temp supplied in user units to F - /// - /// Temp in configured units - /// Temp in F - public double ConvertUserTempToF(double value) - { - if (cumulus.Units.Temp == 1) - { - return value; - } - else - { - // C - return MeteoLib.CToF(value); - } - } - - /// - /// Converts wind supplied in m/s to user units - /// - /// Wind in m/s - /// Wind in configured units - public double ConvertWindMSToUser(double value) - { - switch (cumulus.Units.Wind) - { - case 0: - return value; - case 1: - return value * 2.23693629; - case 2: - return value * 3.6; - case 3: - return value * 1.94384449; - default: - return 0; - } - } - - /// - /// Converts wind supplied in mph to user units - /// - /// Wind in mph - /// Wind in configured units - public double ConvertWindMPHToUser(double value) - { - switch (cumulus.Units.Wind) - { - case 0: - return value * 0.44704; - case 1: - return value; - case 2: - return value * 1.60934; - case 3: - return value * 0.868976; - default: - return 0; - } - } - - /// - /// Converts wind in user units to m/s - /// - /// - /// - public double ConvertUserWindToMS(double value) - { - switch (cumulus.Units.Wind) - { - case 0: - return value; - case 1: - return value / 2.23693629; - case 2: - return value / 3.6F; - case 3: - return value / 1.94384449; - default: - return 0; - } - } - - /// - /// Converts value in kilometres to distance unit based on users configured wind units - /// - /// - /// Wind in configured units - public double ConvertKmtoUserUnits(double val) - { - switch (cumulus.Units.Wind) - { - case 0: // m/s - case 2: // km/h - return val; - case 1: // mph - return val * 0.621371; - case 3: // knots - return val * 0.539957; - } - return val; - } - - /// - /// Converts windrun supplied in user units to km - /// - /// Windrun in configured units - /// Wind in km - public double ConvertWindRunToKm(double value) - { - switch (cumulus.Units.Wind) - { - case 0: // m/s - case 2: // km/h - return value; - case 1: // mph - return value / 0.621371192; - case 3: // knots - return value / 0.539957; - default: - return 0; - } - } - - /// - /// Converts windrun supplied in user units to miles - /// - /// Windrun in configured units - /// Wind in mi - public double ConvertWindRunToMi(double value) - { - switch (cumulus.Units.Wind) - { - case 0: // m/s - case 2: // km/h - return value * 0.621371192; - case 1: // mph - return value; - case 3: // knots - return value / 0.8689762; - default: - return 0; - } - } - - /// - /// Converts windrun supplied in user units to nautical miles - /// - /// Windrun in configured units - /// Wind in Nm - public double ConvertWindRunToNm(double value) - { - switch (cumulus.Units.Wind) - { - case 0: // m/s - case 2: // km/h - return value * 0.539956803; - case 1: // mph - return value * 0.8689762; - case 3: // knots - return value; - default: - return 0; - } - } - - public double ConvertUserWindToKPH(double wind) // input is in Units.Wind units, convert to km/h - { - switch (cumulus.Units.Wind) - { - case 0: // m/s - return wind * 3.6; - case 1: // mph - return wind * 1.609344; - case 2: // kph - return wind; - case 3: // knots - return wind * 1.852; - default: - return wind; - } - } - - /// - /// Converts rain in mm to units in use - /// - /// Rain in mm - /// Rain in configured units - public virtual double ConvertRainMMToUser(double value) - { - return cumulus.Units.Rain == 1 ? value * 0.0393700787 : value; - } - - /// - /// Converts rain in inches to units in use - /// - /// Rain in mm - /// Rain in configured units - public virtual double ConvertRainINToUser(double value) - { - return cumulus.Units.Rain == 1 ? value : value * 25.4; - } - - /// - /// Converts rain in units in use to mm - /// - /// Rain in configured units - /// Rain in mm - public virtual double ConvertUserRainToMM(double value) - { - return cumulus.Units.Rain == 1 ? value / 0.0393700787 : value; - } - - /// - /// Convert pressure in mb to units in use - /// - /// pressure in mb - /// pressure in configured units - public double ConvertPressMBToUser(double value) - { - return cumulus.Units.Press == 2 ? value * 0.0295333727 : value; - } - - /// - /// Convert pressure in inHg to units in use - /// - /// pressure in mb - /// pressure in configured units - public double ConvertPressINHGToUser(double value) - { - return cumulus.Units.Press == 2 ? value : value * 33.8638866667; - } - - /// - /// Convert pressure in units in use to mb - /// - /// pressure in configured units - /// pressure in mb - public double ConvertUserPressToMB(double value) - { - return cumulus.Units.Press == 2 ? value / 0.0295333727 : value; - } - - /// - /// Convert pressure in units in use to inHg - /// - /// pressure in configured units - /// pressure in mb - public double ConvertUserPressToIN(double value) - { - return cumulus.Units.Press == 2 ? value : value * 0.0295333727; - } - public string CompassPoint(int bearing) { return bearing == 0 ? "-" : cumulus.Trans.compassp[(((bearing * 100) + 1125) % 36000) / 2250]; @@ -8539,7 +8331,7 @@ public void DoTrendValues(DateTime ts, bool rollover = false) } // Convert for display - //trendval = ConvertPressMBToUser(presstrendval); + //trendval = ConvertUnits.PressMBToUser(presstrendval); } } catch @@ -8565,7 +8357,7 @@ public void DoTrendValues(DateTime ts, bool rollover = false) // calculate and display rainfall in last hour - if (Raincounter < retVals[0].raincounter) + if (RainCounter < retVals[0].raincounter) { // rain total is not available or has gone down, assume it was reset to zero, just use zero RainLastHour = 0; @@ -8573,14 +8365,14 @@ public void DoTrendValues(DateTime ts, bool rollover = false) else { // normal case - trendval = Raincounter - retVals[0].raincounter; + trendval = RainCounter - retVals[0].raincounter; // Round value as some values may have been read from log file and already rounded trendval = Math.Round(trendval, cumulus.RainDPlaces); var tempRainLastHour = trendval * cumulus.Calib.Rain.Mult; - if (ConvertUserRainToMM(tempRainLastHour) > cumulus.Spike.MaxHourlyRain) + if (tempRainLastHour > cumulus.Spike.MaxHourlyRain) { // ignore cumulus.LogSpikeRemoval("Max hourly rainfall spike value exceed"); @@ -8636,13 +8428,13 @@ public void DoTrendValues(DateTime ts, bool rollover = false) { retVals = RecentDataDb.Query("select raincounter from RecentData where Timestamp >= ? order by Timestamp limit 1", ts.AddMinutes(-5.5)); - if (retVals.Count != 1 || Raincounter < retVals[0].raincounter) + if (retVals.Count != 1 || RainCounter < retVals[0].raincounter) { RainRate = 0; } else { - var raindiff = Math.Round(Raincounter - retVals[0].raincounter, cumulus.RainDPlaces); + var raindiff = Math.Round(RainCounter - retVals[0].raincounter, cumulus.RainDPlaces); //cumulus.LogMessage("raindiff = " + raindiff); var timediffhours = 1.0 / 12.0; @@ -8655,11 +8447,11 @@ public void DoTrendValues(DateTime ts, bool rollover = false) tempRainRate = 0; } - if (ConvertUserRainToMM(tempRainRate) > cumulus.Spike.MaxRainRate) + if (ConvertUnits.UserRainToMM(tempRainRate) > cumulus.Spike.MaxRainRate) { // ignore cumulus.LogSpikeRemoval("Max rainfall rate spike value exceed"); - cumulus.LogSpikeRemoval($"Rate value = {ConvertUserRainToMM(tempRainRate):F2} SpikeMaxRainRate = {cumulus.Spike.MaxRainRate:F2}"); + cumulus.LogSpikeRemoval($"Rate value = {ConvertUnits.UserRainToMM(tempRainRate):F2} SpikeMaxRainRate = {cumulus.Spike.MaxRainRate:F2}"); lastSpikeRemoval = DateTime.Now; cumulus.SpikeAlarm.LastMessage = $"Max rainfall rate greater than spike value - Value={tempRainRate:F1}"; cumulus.SpikeAlarm.Triggered = true; @@ -8711,13 +8503,13 @@ public void DoTrendValues(DateTime ts, bool rollover = false) { retVals = RecentDataDb.Query("select raincounter from RecentData where Timestamp >= ? order by Timestamp limit 1", ts.AddDays(-1)); - if (retVals.Count != 1 || Raincounter < retVals[0].raincounter) + if (retVals.Count != 1 || RainCounter < retVals[0].raincounter) { RainLast24Hour = 0; } else { - trendval = Math.Round(Raincounter - retVals[0].raincounter, cumulus.RainDPlaces); + trendval = Math.Round(RainCounter - retVals[0].raincounter, cumulus.RainDPlaces); if (trendval < 0) { @@ -9294,11 +9086,14 @@ public string LoadDayFile() { int addedEntries = 0; + string msg = string.Empty; + cumulus.LogMessage($"LoadDayFile: Attempting to load the day file"); if (File.Exists(cumulus.DayFileName)) { int linenum = 0; int errorCount = 0; + int duplicateCount = 0; var watch = Stopwatch.StartNew(); @@ -9317,18 +9112,29 @@ public string LoadDayFile() linenum++; string Line = sr.ReadLine(); - DayFile.Add(ParseDayFileRec(Line)); + var newRec = ParseDayFileRec(Line); + + if (DayFile.Any(x => x.Date == newRec.Date)) + { + cumulus.LogErrorMessage($"ERROR: Duplicate entry in dayfile for {newRec.Date:d}"); + msg += $"ERROR: Duplicate entry in dayfile for {newRec.Date:d}
"; + duplicateCount++; + } + + DayFile.Add(newRec); addedEntries++; } catch (Exception e) { cumulus.LogWarningMessage($"LoadDayFile: Error at line {linenum} of {cumulus.DayFileName} : {e.Message}"); + msg += $"Error at line {linenum} of {cumulus.DayFileName}
"; cumulus.LogMessage("Please edit the file to correct the error"); errorCount++; if (errorCount >= 20) { cumulus.LogErrorMessage($"LoadDayFile: Too many errors reading {cumulus.DayFileName} - aborting load of daily data"); + msg += "Too many errors reading dayfile, aborting
"; } } } while (!(sr.EndOfStream || errorCount >= 20)); @@ -9338,20 +9144,27 @@ public string LoadDayFile() watch.Stop(); cumulus.LogDebugMessage($"LoadDayFile: Dayfile parse = {watch.ElapsedMilliseconds} ms"); + if (duplicateCount > 0) + { + msg += $"Found {duplicateCount} duplicate entries, please correct your dayfile and try again"; + cumulus.LogErrorMessage($"LoadDayFile: Found {duplicateCount} duplicate entries, please correct your dayfile and try again"); + return msg; + } } catch (Exception e) { cumulus.LogErrorMessage($"LoadDayFile: Error at line {linenum} of {cumulus.DayFileName} : {e.Message}"); cumulus.LogMessage("Please edit the file to correct the error"); + msg += $"Error at line {linenum} of {cumulus.DayFileName} : {e.Message}
"; } - var msg = $"LoadDayFile: Loaded {addedEntries} entries to recent daily data list"; - cumulus.LogMessage(msg); + cumulus.LogMessage($"LoadDayFile: Loaded {addedEntries} entries to recent daily data list"); + msg += $"Loaded {addedEntries} entries to recent daily data list"; return msg; } else { - var msg = "LoadDayFile: No Dayfile found - No entries added to recent daily data list"; + msg = "LoadDayFile: No Dayfile found - No entries added to recent daily data list"; cumulus.LogErrorMessage(msg); return msg; } @@ -9697,7 +9510,7 @@ internal void UpdateMQTT() { if (cumulus.MQTT.EnableDataUpdate) { - MqttPublisher.UpdateMQTTfeed("DataUpdate"); + MqttPublisher.UpdateMQTTfeed("DataUpdate", null); } } @@ -10122,47 +9935,12 @@ public string BetelCast(double z_hpa, int z_month, string z_wind, int z_trend, b public int Forecastnumber { get; set; } - /// - /// Takes speed in user units, returns Bft number - /// - /// - /// - public int Beaufort(double speed) - { - double windspeedMS = ConvertUserWindToMS(speed); - if (windspeedMS < 0.3) - return 0; - else if (windspeedMS < 1.6) - return 1; - else if (windspeedMS < 3.4) - return 2; - else if (windspeedMS < 5.5) - return 3; - else if (windspeedMS < 8.0) - return 4; - else if (windspeedMS < 10.8) - return 5; - else if (windspeedMS < 13.9) - return 6; - else if (windspeedMS < 17.2) - return 7; - else if (windspeedMS < 20.8) - return 8; - else if (windspeedMS < 24.5) - return 9; - else if (windspeedMS < 28.5) - return 10; - else if (windspeedMS < 32.7) - return 11; - else return 12; - } // This overridden in each station implementation public abstract void Stop(); public void ReadAlltimeIniFile() { - cumulus.LogMessage(Path.GetFullPath(cumulus.AlltimeIniFile)); IniFile ini = new IniFile(cumulus.AlltimeIniFile); AllTime.HighTemp.Val = ini.GetValue("Temperature", "hightempvalue", Cumulus.DefaultHiVal); @@ -10982,36 +10760,36 @@ public string GetWCloudURL(out string pwstring, DateTime timestamp) StringBuilder sb = new StringBuilder($"https://api.weathercloud.net/v01/set?wid={cumulus.WCloud.ID}&key={pwstring}"); //Temperature - sb.Append("&tempin=" + (int) Math.Round(ConvertUserTempToC(IndoorTemperature) * 10)); - sb.Append("&temp=" + (int) Math.Round(ConvertUserTempToC(OutdoorTemperature) * 10)); - sb.Append("&chill=" + (int) Math.Round(ConvertUserTempToC(WindChill) * 10)); - sb.Append("&dew=" + (int) Math.Round(ConvertUserTempToC(OutdoorDewpoint) * 10)); - sb.Append("&heat=" + (int) Math.Round(ConvertUserTempToC(HeatIndex) * 10)); + sb.Append("&tempin=" + (int) Math.Round(ConvertUnits.UserTempToC(IndoorTemperature) * 10)); + sb.Append("&temp=" + (int) Math.Round(ConvertUnits.UserTempToC(OutdoorTemperature) * 10)); + sb.Append("&chill=" + (int) Math.Round(ConvertUnits.UserTempToC(WindChill) * 10)); + sb.Append("&dew=" + (int) Math.Round(ConvertUnits.UserTempToC(OutdoorDewpoint) * 10)); + sb.Append("&heat=" + (int) Math.Round(ConvertUnits.UserTempToC(HeatIndex) * 10)); // Humidity sb.Append("&humin=" + IndoorHumidity); sb.Append("&hum=" + OutdoorHumidity); // Wind - sb.Append("&wspd=" + (int) Math.Round(ConvertUserWindToMS(WindLatest) * 10)); - sb.Append("&wspdhi=" + (int) Math.Round(ConvertUserWindToMS(RecentMaxGust) * 10)); - sb.Append("&wspdavg=" + (int) Math.Round(ConvertUserWindToMS(WindAverage) * 10)); + sb.Append("&wspd=" + (int) Math.Round(ConvertUnits.UserWindToMS(WindLatest) * 10)); + sb.Append("&wspdhi=" + (int) Math.Round(ConvertUnits.UserWindToMS(RecentMaxGust) * 10)); + sb.Append("&wspdavg=" + (int) Math.Round(ConvertUnits.UserWindToMS(WindAverage) * 10)); // Wind Direction sb.Append("&wdir=" + Bearing); sb.Append("&wdiravg=" + AvgBearing); // Pressure - sb.Append("&bar=" + (int) Math.Round(ConvertUserPressToMB(Pressure) * 10)); + sb.Append("&bar=" + (int) Math.Round(ConvertUnits.UserPressToMB(Pressure) * 10)); // rain - sb.Append("&rain=" + (int) Math.Round(ConvertUserRainToMM(RainToday) * 10)); - sb.Append("&rainrate=" + (int) Math.Round(ConvertUserRainToMM(RainRate) * 10)); + sb.Append("&rain=" + (int) Math.Round(ConvertUnits.UserRainToMM(RainToday) * 10)); + sb.Append("&rainrate=" + (int) Math.Round(ConvertUnits.UserRainToMM(RainRate) * 10)); // ET if (cumulus.WCloud.SendSolar && cumulus.Manufacturer == cumulus.DAVIS) { - sb.Append("&et=" + (int) Math.Round(ConvertUserRainToMM(ET) * 10)); + sb.Append("&et=" + (int) Math.Round(ConvertUnits.UserRainToMM(ET) * 10)); } // solar @@ -11227,7 +11005,7 @@ public string GetAwekasURLv4(out string pwstring, DateTime timestamp) // indoor temp/humidity if (cumulus.AWEKAS.SendIndoor) { - sb.Append("indoortemp=" + ConvertUserTempToC(IndoorTemperature).ToString("F1", InvC)); + sb.Append("indoortemp=" + ConvertUnits.UserTempToC(IndoorTemperature).ToString("F1", InvC)); sb.Append("&indoorhumidity=" + IndoorHumidity); started = true; } @@ -11237,7 +11015,7 @@ public string GetAwekasURLv4(out string pwstring, DateTime timestamp) for (var i = 1; i <= 4; i++) { if (started) sb.Append('&'); else started = true; - sb.Append($"soiltemp{i}=" + ConvertUserTempToC(SoilTemp[i]).ToString("F1", InvC)); + sb.Append($"soiltemp{i}=" + ConvertUnits.UserTempToC(SoilTemp[i]).ToString("F1", InvC)); } } @@ -11309,16 +11087,16 @@ public string GetAwekasURLv4(out string pwstring, DateTime timestamp) sb.Append(cumulus.AWEKAS.ID + sep); // 1 sb.Append(pwstring + sep); // 2 sb.Append(timestamp.ToString("dd'.'MM'.'yyyy';'HH':'mm") + sep); // 3 + 4 - sb.Append(ConvertUserTempToC(OutdoorTemperature).ToString("F1", InvC) + sep); // 5 + sb.Append(ConvertUnits.UserTempToC(OutdoorTemperature).ToString("F1", InvC) + sep); // 5 sb.Append(OutdoorHumidity + sep); // 6 - sb.Append(ConvertUserPressToMB(Pressure).ToString("F1", InvC) + sep); // 7 - sb.Append(ConvertUserRainToMM(RainSinceMidnight).ToString("F1", InvC) + sep); // 8 - was RainToday in v2 - sb.Append(ConvertUserWindToKPH(WindAverage).ToString("F1", InvC) + sep); // 9 + sb.Append(ConvertUnits.UserPressToMB(Pressure).ToString("F1", InvC) + sep); // 7 + sb.Append(ConvertUnits.UserRainToMM(RainSinceMidnight).ToString("F1", InvC) + sep); // 8 - was RainToday in v2 + sb.Append(ConvertUnits.UserWindToKPH(WindAverage).ToString("F1", InvC) + sep); // 9 sb.Append(AvgBearing + sep); // 10 sb.Append(sep + sep + sep); // 11/12/13 - condition and warning, snow height sb.Append(cumulus.AWEKAS.Lang + sep); // 14 sb.Append(presstrend + sep); // 15 - sb.Append(ConvertUserWindToKPH(RecentMaxGust).ToString("F1", InvC) + sep); // 16 + sb.Append(ConvertUnits.UserWindToKPH(RecentMaxGust).ToString("F1", InvC) + sep); // 16 if (cumulus.AWEKAS.SendSolar) sb.Append(SolarRad.ToString("F1", InvC) + sep); // 17 @@ -11345,22 +11123,22 @@ public string GetAwekasURLv4(out string pwstring, DateTime timestamp) } if (cumulus.AWEKAS.SendSoilTemp) - sb.Append(ConvertUserTempToC(SoilTemp[1]).ToString("F1", InvC) + sep); // 21 + sb.Append(ConvertUnits.UserTempToC(SoilTemp[1]).ToString("F1", InvC) + sep); // 21 else sb.Append(sep); - sb.Append(ConvertUserRainToMM(RainRate).ToString("F1", InvC) + sep); // 22 + sb.Append(ConvertUnits.UserRainToMM(RainRate).ToString("F1", InvC) + sep); // 22 sb.Append("Cum_" + cumulus.Version + sep); // 23 sb.Append(sep + sep); // 24/25 location for mobile - sb.Append(ConvertUserTempToC(HiLoToday.LowTemp).ToString("F1", InvC) + sep); // 26 - sb.Append(ConvertUserTempToC(AvgTemp).ToString("F1", InvC) + sep); // 27 - sb.Append(ConvertUserTempToC(HiLoToday.HighTemp).ToString("F1", InvC) + sep); // 28 - sb.Append(ConvertUserTempToC(ThisMonth.LowTemp.Val).ToString("F1", InvC) + sep);// 29 + sb.Append(ConvertUnits.UserTempToC(HiLoToday.LowTemp).ToString("F1", InvC) + sep); // 26 + sb.Append(ConvertUnits.UserTempToC(AvgTemp).ToString("F1", InvC) + sep); // 27 + sb.Append(ConvertUnits.UserTempToC(HiLoToday.HighTemp).ToString("F1", InvC) + sep); // 28 + sb.Append(ConvertUnits.UserTempToC(ThisMonth.LowTemp.Val).ToString("F1", InvC) + sep);// 29 sb.Append(sep); // 30 avg temp this month - sb.Append(ConvertUserTempToC(ThisMonth.HighTemp.Val).ToString("F1", InvC) + sep);// 31 - sb.Append(ConvertUserTempToC(ThisYear.LowTemp.Val).ToString("F1", InvC) + sep); // 32 + sb.Append(ConvertUnits.UserTempToC(ThisMonth.HighTemp.Val).ToString("F1", InvC) + sep);// 31 + sb.Append(ConvertUnits.UserTempToC(ThisYear.LowTemp.Val).ToString("F1", InvC) + sep); // 32 sb.Append(sep); // 33 avg temp this year - sb.Append(ConvertUserTempToC(ThisYear.HighTemp.Val).ToString("F1", InvC) + sep);// 34 + sb.Append(ConvertUnits.UserTempToC(ThisYear.HighTemp.Val).ToString("F1", InvC) + sep);// 34 sb.Append(HiLoToday.LowHumidity + sep); // 35 sb.Append(sep); // 36 avg hum today sb.Append(HiLoToday.HighHumidity + sep); // 37 @@ -11370,37 +11148,37 @@ public string GetAwekasURLv4(out string pwstring, DateTime timestamp) sb.Append(ThisYear.LowHumidity.Val + sep); // 41 sb.Append(sep); // 42 avg hum this year sb.Append(ThisYear.HighHumidity.Val + sep); // 43 - sb.Append(ConvertUserPressToMB(HiLoToday.LowPress).ToString("F1", InvC) + sep); // 44 + sb.Append(ConvertUnits.UserPressToMB(HiLoToday.LowPress).ToString("F1", InvC) + sep); // 44 sb.Append(sep); // 45 avg press today - sb.Append(ConvertUserPressToMB(HiLoToday.HighPress).ToString("F1", InvC) + sep);// 46 - sb.Append(ConvertUserPressToMB(ThisMonth.LowPress.Val).ToString("F1", InvC) + sep); // 47 + sb.Append(ConvertUnits.UserPressToMB(HiLoToday.HighPress).ToString("F1", InvC) + sep);// 46 + sb.Append(ConvertUnits.UserPressToMB(ThisMonth.LowPress.Val).ToString("F1", InvC) + sep); // 47 sb.Append(sep); // 48 avg press this month - sb.Append(ConvertUserPressToMB(ThisMonth.HighPress.Val).ToString("F1", InvC) + sep); // 49 - sb.Append(ConvertUserPressToMB(ThisYear.LowPress.Val).ToString("F1", InvC) + sep); // 50 + sb.Append(ConvertUnits.UserPressToMB(ThisMonth.HighPress.Val).ToString("F1", InvC) + sep); // 49 + sb.Append(ConvertUnits.UserPressToMB(ThisYear.LowPress.Val).ToString("F1", InvC) + sep); // 50 sb.Append(sep); // 51 avg press this year - sb.Append(ConvertUserPressToMB(ThisYear.HighPress.Val).ToString("F1", InvC) + sep); // 52 + sb.Append(ConvertUnits.UserPressToMB(ThisYear.HighPress.Val).ToString("F1", InvC) + sep); // 52 sb.Append(sep + sep); // 53/54 min/avg wind today - sb.Append(ConvertUserWindToKPH(HiLoToday.HighWind).ToString("F1", InvC) + sep); // 55 + sb.Append(ConvertUnits.UserWindToKPH(HiLoToday.HighWind).ToString("F1", InvC) + sep); // 55 sb.Append(sep + sep); // 56/57 min/avg wind this month - sb.Append(ConvertUserWindToKPH(ThisMonth.HighWind.Val).ToString("F1", InvC) + sep); // 58 + sb.Append(ConvertUnits.UserWindToKPH(ThisMonth.HighWind.Val).ToString("F1", InvC) + sep); // 58 sb.Append(sep + sep); // 59/60 min/avg wind this year - sb.Append(ConvertUserWindToKPH(ThisYear.HighWind.Val).ToString("F1", InvC) + sep); // 61 + sb.Append(ConvertUnits.UserWindToKPH(ThisYear.HighWind.Val).ToString("F1", InvC) + sep); // 61 sb.Append(sep + sep); // 62/63 min/avg gust today - sb.Append(ConvertUserWindToKPH(HiLoToday.HighGust).ToString("F1", InvC) + sep); // 64 + sb.Append(ConvertUnits.UserWindToKPH(HiLoToday.HighGust).ToString("F1", InvC) + sep); // 64 sb.Append(sep + sep); // 65/66 min/avg gust this month - sb.Append(ConvertUserWindToKPH(ThisMonth.HighGust.Val).ToString("F1", InvC) + sep); // 67 + sb.Append(ConvertUnits.UserWindToKPH(ThisMonth.HighGust.Val).ToString("F1", InvC) + sep); // 67 sb.Append(sep + sep); // 68/69 min/avg gust this year - sb.Append(ConvertUserWindToKPH(ThisYear.HighGust.Val).ToString("F1", InvC) + sep); // 70 + sb.Append(ConvertUnits.UserWindToKPH(ThisYear.HighGust.Val).ToString("F1", InvC) + sep); // 70 sb.Append(sep + sep + sep); // 71/72/73 avg wind bearing today/month/year - sb.Append(ConvertUserRainToMM(RainLast24Hour).ToString("F1", InvC) + sep); // 74 - sb.Append(ConvertUserRainToMM(RainMonth).ToString("F1", InvC) + sep); // 75 - sb.Append(ConvertUserRainToMM(RainYear).ToString("F1", InvC) + sep); // 76 + sb.Append(ConvertUnits.UserRainToMM(RainLast24Hour).ToString("F1", InvC) + sep); // 74 + sb.Append(ConvertUnits.UserRainToMM(RainMonth).ToString("F1", InvC) + sep); // 75 + sb.Append(ConvertUnits.UserRainToMM(RainYear).ToString("F1", InvC) + sep); // 76 sb.Append(sep); // 77 avg rain rate today - sb.Append(ConvertUserRainToMM(HiLoToday.HighRainRate).ToString("F1", InvC) + sep); // 78 + sb.Append(ConvertUnits.UserRainToMM(HiLoToday.HighRainRate).ToString("F1", InvC) + sep); // 78 sb.Append(sep); // 79 avg rain rate this month - sb.Append(ConvertUserRainToMM(ThisMonth.HighRainRate.Val).ToString("F1", InvC) + sep); // 80 + sb.Append(ConvertUnits.UserRainToMM(ThisMonth.HighRainRate.Val).ToString("F1", InvC) + sep); // 80 sb.Append(sep); // 81 avg rain rate this year - sb.Append(ConvertUserRainToMM(ThisYear.HighRainRate.Val).ToString("F1", InvC) + sep); // 82 + sb.Append(ConvertUnits.UserRainToMM(ThisYear.HighRainRate.Val).ToString("F1", InvC) + sep); // 82 sb.Append(sep); // 83 avg solar today if (cumulus.AWEKAS.SendSolar) sb.Append(HiLoToday.HighSolar.ToString("F1", InvC)); // 84 @@ -11643,16 +11421,16 @@ public string GetWindGuruURL(out string uidstring, DateTime timestamp) URL.Append("&salt=" + salt); URL.Append("&hash=" + hash); URL.Append("&interval=" + cumulus.WindGuru.Interval * 60); - URL.Append("&wind_avg=" + ConvertUserWindToKnots(avgwind).ToString("F1", InvC)); - URL.Append("&wind_max=" + ConvertUserWindToKnots(maxwind).ToString("F1", InvC)); - URL.Append("&wind_min=" + ConvertUserWindToKnots(minwind).ToString("F1", InvC)); + URL.Append("&wind_avg=" + ConvertUnits.UserWindToKnots(avgwind).ToString("F1", InvC)); + URL.Append("&wind_max=" + ConvertUnits.UserWindToKnots(maxwind).ToString("F1", InvC)); + URL.Append("&wind_min=" + ConvertUnits.UserWindToKnots(minwind).ToString("F1", InvC)); URL.Append("&wind_direction=" + AvgBearing); - URL.Append("&temperature=" + ConvertUserTempToC(OutdoorTemperature).ToString("F1", InvC)); + URL.Append("&temperature=" + ConvertUnits.UserTempToC(OutdoorTemperature).ToString("F1", InvC)); URL.Append("&rh=" + OutdoorHumidity); - URL.Append("&mslp=" + ConvertUserPressureToHPa(Pressure).ToString("F1", InvC)); + URL.Append("&mslp=" + ConvertUnits.UserPressureToHPa(Pressure).ToString("F1", InvC)); if (cumulus.WindGuru.SendRain) { - URL.Append("&precip=" + ConvertUserRainToMM(RainLastHour).ToString("F1", InvC)); + URL.Append("&precip=" + ConvertUnits.UserRainToMM(RainLastHour).ToString("F1", InvC)); URL.Append("&precip_interval=3600"); } @@ -11665,14 +11443,14 @@ public string GetOpenWeatherMapData(DateTime timestamp) var invC = new CultureInfo(""); sb.Append($"\"dt\":{Utils.ToUnixTime(timestamp)},"); - sb.Append($"\"temperature\":{Math.Round(ConvertUserTempToC(OutdoorTemperature), 1).ToString(invC)},"); + sb.Append($"\"temperature\":{Math.Round(ConvertUnits.UserTempToC(OutdoorTemperature), 1).ToString(invC)},"); sb.Append($"\"wind_deg\":{AvgBearing},"); - sb.Append($"\"wind_speed\":{Math.Round(ConvertUserWindToMS(WindAverage), 1).ToString(invC)},"); - sb.Append($"\"wind_gust\":{Math.Round(ConvertUserWindToMS(RecentMaxGust), 1).ToString(invC)},"); - sb.Append($"\"pressure\":{Math.Round(ConvertUserPressureToHPa(Pressure), 1).ToString(invC)},"); + sb.Append($"\"wind_speed\":{Math.Round(ConvertUnits.UserWindToMS(WindAverage), 1).ToString(invC)},"); + sb.Append($"\"wind_gust\":{Math.Round(ConvertUnits.UserWindToMS(RecentMaxGust), 1).ToString(invC)},"); + sb.Append($"\"pressure\":{Math.Round(ConvertUnits.UserPressureToHPa(Pressure), 1).ToString(invC)},"); sb.Append($"\"humidity\":{OutdoorHumidity},"); - sb.Append($"\"rain_1h\":{Math.Round(ConvertUserRainToMM(RainLastHour), 1).ToString(invC)},"); - sb.Append($"\"rain_24h\":{Math.Round(ConvertUserRainToMM(RainLast24Hour), 1).ToString(invC)}"); + sb.Append($"\"rain_1h\":{Math.Round(ConvertUnits.UserRainToMM(RainLastHour), 1).ToString(invC)},"); + sb.Append($"\"rain_24h\":{Math.Round(ConvertUnits.UserRainToMM(RainLast24Hour), 1).ToString(invC)}"); sb.Append("}]"); return sb.ToString(); @@ -11680,18 +11458,18 @@ public string GetOpenWeatherMapData(DateTime timestamp) private string PressINstr(double pressure) { - return ConvertUserPressToIN(pressure).ToString("F3", CultureInfo.InvariantCulture); + return ConvertUnits.UserPressToIN(pressure).ToString("F3", CultureInfo.InvariantCulture); } private string PressPAstr(double pressure) { // return value to 0.1 hPa - return (ConvertUserPressToMB(pressure) / 100).ToString("F4", CultureInfo.InvariantCulture); + return (ConvertUnits.UserPressToMB(pressure) / 100).ToString("F4", CultureInfo.InvariantCulture); } private string WindMPHStr(double wind) { - var windMPH = ConvertUserWindToMPH(wind); + var windMPH = ConvertUnits.UserWindToMPH(wind); if (cumulus.StationOptions.RoundWindSpeed) windMPH = Math.Round(windMPH); @@ -11700,7 +11478,7 @@ private string WindMPHStr(double wind) private string WindMSStr(double wind) { - var windMS = ConvertUserWindToMS(wind); + var windMS = ConvertUnits.UserWindToMS(wind); if (cumulus.StationOptions.RoundWindSpeed) windMS = Math.Round(windMS); @@ -11714,7 +11492,7 @@ private string WindMSStr(double wind) /// private string RainINstr(double rain) { - return ConvertUserRainToIn(rain).ToString("F2", CultureInfo.InvariantCulture); + return ConvertUnits.UserRainToIN(rain).ToString("F2", CultureInfo.InvariantCulture); } /// @@ -11724,7 +11502,7 @@ private string RainINstr(double rain) /// private string RainMMstr(double rain) { - return ConvertUserRainToMM(rain).ToString("F2", CultureInfo.InvariantCulture); + return ConvertUnits.UserRainToMM(rain).ToString("F2", CultureInfo.InvariantCulture); } /// @@ -11734,7 +11512,7 @@ private string RainMMstr(double rain) /// private string TempFstr(double temp) { - return ConvertUserTempToF(temp).ToString("F1", CultureInfo.InvariantCulture); + return ConvertUnits.UserTempToF(temp).ToString("F1", CultureInfo.InvariantCulture); } /// @@ -11744,7 +11522,7 @@ private string TempFstr(double temp) /// private string TempCstr(double temp) { - return ConvertUserTempToC(temp).ToString("F1", CultureInfo.InvariantCulture); + return ConvertUnits.UserTempToC(temp).ToString("F1", CultureInfo.InvariantCulture); } public string GetPWSURL(out string pwstring, DateTime timestamp) @@ -11849,18 +11627,6 @@ public string GetWOWURL(out string pwstring, DateTime timestamp) return URL.ToString(); } - public double ConvertUserRainToIN(double rain) - { - if (cumulus.Units.Rain == 0) - { - return rain * 0.0393700787; - } - else - { - return rain; - } - } - private string alltimejsonformat(AllTimeRec item, string unit, string valueformat, string dateformat) { return $"[\"{item.Desc}\",\"{item.GetValString(valueformat)} {unit}\",\"{item.GetTsString(dateformat)}\"]"; @@ -14514,7 +14280,7 @@ public string GetAllDegreeDaysGraphData(bool local) if (cumulus.GraphOptions.Visible.GrowingDegreeDays1.IsVisible(local)) { // growing degree days - var gdd = MeteoLib.GrowingDegreeDays(ConvertUserTempToC(DayFile[i].HighTemp), ConvertUserTempToC(DayFile[i].LowTemp), ConvertUserTempToC(cumulus.GrowingBase1), cumulus.GrowingCap30C); + var gdd = MeteoLib.GrowingDegreeDays(ConvertUnits.UserTempToC(DayFile[i].HighTemp), ConvertUnits.UserTempToC(DayFile[i].LowTemp), ConvertUnits.UserTempToC(cumulus.GrowingBase1), cumulus.GrowingCap30C); // annual accumulation annualGrowingDegDays1 += gdd; @@ -14525,7 +14291,7 @@ public string GetAllDegreeDaysGraphData(bool local) if (cumulus.GraphOptions.Visible.GrowingDegreeDays2.IsVisible(local)) { // growing degree days - var gdd = MeteoLib.GrowingDegreeDays(ConvertUserTempToC(DayFile[i].HighTemp), ConvertUserTempToC(DayFile[i].LowTemp), ConvertUserTempToC(cumulus.GrowingBase2), cumulus.GrowingCap30C); + var gdd = MeteoLib.GrowingDegreeDays(ConvertUnits.UserTempToC(DayFile[i].HighTemp), ConvertUnits.UserTempToC(DayFile[i].LowTemp), ConvertUnits.UserTempToC(cumulus.GrowingBase2), cumulus.GrowingCap30C); // annual accumulation annualGrowingDegDays2 += gdd; @@ -14804,6 +14570,61 @@ internal string GetCurrentData() } string stormRainStart = StartOfStorm == DateTime.MinValue ? "-----" : StartOfStorm.ToString("d"); + var alarms = new List(); + if (cumulus.NewRecordAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.NewRecordAlarm.Id, cumulus.NewRecordAlarm.Triggered)); + if (cumulus.LowTempAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.LowTempAlarm.Id, cumulus.LowTempAlarm.Triggered)); + if (cumulus.HighTempAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.HighTempAlarm.Id, cumulus.HighTempAlarm.Triggered)); + if (cumulus.TempChangeAlarm.Enabled) + { + alarms.Add(new DashboardAlarms(cumulus.TempChangeAlarm.IdUp, cumulus.TempChangeAlarm.UpTriggered)); + alarms.Add(new DashboardAlarms(cumulus.TempChangeAlarm.IdDown, cumulus.TempChangeAlarm.DownTriggered)); + } + if (cumulus.HighRainTodayAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.HighRainTodayAlarm.Id, cumulus.HighRainTodayAlarm.Triggered)); + if (cumulus.HighRainRateAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.HighRainRateAlarm.Id, cumulus.HighRainRateAlarm.Triggered)); + if (cumulus.IsRainingAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.IsRainingAlarm.Id, cumulus.IsRainingAlarm.Triggered)); + if (cumulus.DataStoppedAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.DataStoppedAlarm.Id, cumulus.DataStoppedAlarm.Triggered)); + if (cumulus.LowPressAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.LowPressAlarm.Id, cumulus.LowPressAlarm.Triggered)); + if (cumulus.HighPressAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.HighPressAlarm.Id, cumulus.HighPressAlarm.Triggered)); + if (cumulus.PressChangeAlarm.Enabled) + { + alarms.Add(new DashboardAlarms(cumulus.PressChangeAlarm.IdUp, cumulus.PressChangeAlarm.UpTriggered)); + alarms.Add(new DashboardAlarms(cumulus.PressChangeAlarm.IdDown, cumulus.PressChangeAlarm.DownTriggered)); + } + if (cumulus.HighGustAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.HighGustAlarm.Id, cumulus.HighGustAlarm.Triggered)); + if (cumulus.HighWindAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.HighWindAlarm.Id, cumulus.HighWindAlarm.Triggered)); + if (cumulus.SensorAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.SensorAlarm.Id, cumulus.SensorAlarm.Triggered)); + if (cumulus.BatteryLowAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.BatteryLowAlarm.Id, cumulus.BatteryLowAlarm.Triggered)); + if (cumulus.SpikeAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.SpikeAlarm.Id, cumulus.SpikeAlarm.Triggered)); + if (cumulus.FtpAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.FtpAlarm.Id, cumulus.FtpAlarm.Triggered)); + if (cumulus.ThirdPartyAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.ThirdPartyAlarm.Id, cumulus.ThirdPartyAlarm.Triggered)); + if (cumulus.MySqlUploadAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.MySqlUploadAlarm.Id, cumulus.MySqlUploadAlarm.Triggered)); + if (cumulus.UpgradeAlarm.Enabled) + alarms.Add(new DashboardAlarms(cumulus.UpgradeAlarm.Id, cumulus.UpgradeAlarm.Triggered)); + + for (var i = 0; i < cumulus.UserAlarms.Count; i++) + { + if (cumulus.UserAlarms[i].Enabled) + alarms.Add(new DashboardAlarms("AlarmUser" + i, cumulus.UserAlarms[i].Triggered)); + } + + var data = new DataStruct(cumulus, OutdoorTemperature, OutdoorHumidity, TempTotalToday / tempsamplestoday, IndoorTemperature, OutdoorDewpoint, WindChill, IndoorHumidity, Pressure, WindLatest, WindAverage, RecentMaxGust, WindRunToday, Bearing, AvgBearing, RainToday, RainYesterday, RainMonth, RainYear, RainRate, RainLastHour, HeatIndex, Humidex, ApparentTemperature, temptrendval, presstrendval, HiLoToday.HighGust, HiLoToday.HighGustTime.ToString(cumulus.ProgramOptions.TimeFormat), HiLoToday.HighWind, @@ -14819,11 +14640,8 @@ internal string GetCurrentData() AllTime.HighPress.Val, AllTime.LowPress.Val, SunshineHours, CompassPoint(DominantWindBearing), LastRainTip, HiLoToday.HighHourlyRain, HiLoToday.HighHourlyRainTime.ToString(cumulus.ProgramOptions.TimeFormat), "F" + cumulus.Beaufort(HiLoToday.HighWind), "F" + cumulus.Beaufort(WindAverage), cumulus.BeaufortDesc(WindAverage), LastDataReadTimestamp.ToString(cumulus.ProgramOptions.TimeFormatLong), DataStopped, StormRain, stormRainStart, CloudBase, cumulus.CloudBaseInFeet ? "ft" : "m", RainLast24Hour, - cumulus.LowTempAlarm.Triggered, cumulus.HighTempAlarm.Triggered, cumulus.TempChangeAlarm.UpTriggered, cumulus.TempChangeAlarm.DownTriggered, cumulus.HighRainTodayAlarm.Triggered, cumulus.HighRainRateAlarm.Triggered, - cumulus.LowPressAlarm.Triggered, cumulus.HighPressAlarm.Triggered, cumulus.PressChangeAlarm.UpTriggered, cumulus.PressChangeAlarm.DownTriggered, cumulus.HighGustAlarm.Triggered, cumulus.HighWindAlarm.Triggered, - cumulus.SensorAlarm.Triggered, cumulus.BatteryLowAlarm.Triggered, cumulus.SpikeAlarm.Triggered, cumulus.UpgradeAlarm.Triggered, cumulus.ThirdPartyAlarm.Triggered, cumulus.MySqlUploadAlarm.Triggered, cumulus.IsRainingAlarm.Triggered, FeelsLike, HiLoToday.HighFeelsLike, HiLoToday.HighFeelsLikeTime.ToString(cumulus.ProgramOptions.TimeFormat), HiLoToday.LowFeelsLike, HiLoToday.LowFeelsLikeTime.ToString(cumulus.ProgramOptions.TimeFormat), - HiLoToday.HighHumidex, HiLoToday.HighHumidexTime.ToString(cumulus.ProgramOptions.TimeFormat)); + HiLoToday.HighHumidex, HiLoToday.HighHumidexTime.ToString(cumulus.ProgramOptions.TimeFormat), alarms); try { @@ -14848,14 +14666,12 @@ internal string GetCurrentData() // Returns true if the gust value exceeds current RecentMaxGust, false if it fails public bool CheckHighGust(double gust, int gustdir, DateTime timestamp) { - // Spike check is in m/s - var windGustMS = ConvertUserWindToMS(gust); - if (((previousGust != 999) && (Math.Abs(windGustMS - previousGust) > cumulus.Spike.GustDiff)) || windGustMS >= cumulus.Limit.WindHigh) + if (gust >= cumulus.Limit.WindHigh) { - cumulus.LogSpikeRemoval("Wind Gust difference greater than specified; reading ignored"); - cumulus.LogSpikeRemoval($"Gust: NewVal={windGustMS:F1} OldVal={previousGust:F1} SpikeGustDiff={cumulus.Spike.GustDiff:F1} HighLimit={cumulus.Limit.WindHigh:F1}"); - lastSpikeRemoval = DateTime.Now; - cumulus.SpikeAlarm.LastMessage = $"Wind Gust difference greater than spike value - NewVal={windGustMS:F1}, OldVal={previousGust:F1}"; + cumulus.LogSpikeRemoval("Wind Gust greater than the limit; reading ignored"); + cumulus.LogSpikeRemoval($"Gust: NewVal={gust:F1} HighLimit={cumulus.Limit.WindHigh:F1}"); + lastSpikeRemoval = timestamp; + cumulus.SpikeAlarm.LastMessage = $"Wind Gust greater than limit - NewVal={gust:F1}, OldVal={cumulus.Limit.WindHigh:F1}"; cumulus.SpikeAlarm.Triggered = true; return false; } @@ -14985,7 +14801,7 @@ public void UpdateAPRS() // 0900 day, use midnight calculation message.Append(APRSrain(RainSinceMidnight)); } - if ((!cumulus.APRS.HumidityCutoff) || (ConvertUserTempToC(OutdoorTemperature) >= -10)) + if ((!cumulus.APRS.HumidityCutoff) || (ConvertUnits.UserTempToC(OutdoorTemperature) >= -10)) { // humidity Hnn message.Append($"h{APRShum(OutdoorHumidity)}"); @@ -15083,7 +14899,7 @@ private string APRSLon(Cumulus cumulus) /// private string APRSwind(double wind) { - var windMPH = Convert.ToInt32(ConvertUserWindToMPH(wind)); + var windMPH = Convert.ToInt32(ConvertUnits.UserWindToMPH(wind)); return windMPH.ToString("D3"); } @@ -15095,7 +14911,7 @@ private string APRSwind(double wind) /// public string APRSpress(double press) { - var press10mb = Convert.ToInt32(ConvertUserPressToMB(press) * 10); + var press10mb = Convert.ToInt32(ConvertUnits.UserPressToMB(press) * 10); return press10mb.ToString("D5"); } @@ -15129,7 +14945,7 @@ public string APRShum(int hum) /// public string APRSrain(double rain) { - var rain100IN = Convert.ToInt32(ConvertUserRainToIN(rain) * 100); + var rain100IN = Convert.ToInt32(ConvertUnits.UserRainToIN(rain) * 100); return rain100IN.ToString("D3"); } diff --git a/CumulusMX/Wizard.cs b/CumulusMX/Wizard.cs index e4995ba7..411ce11a 100644 --- a/CumulusMX/Wizard.cs +++ b/CumulusMX/Wizard.cs @@ -100,9 +100,13 @@ public string GetAlpacaFormData() } }; - var weatherflow = new JsonStationSettingsWeatherFlow() - { deviceid = cumulus.WeatherFlowOptions.WFDeviceId, tcpport = cumulus.WeatherFlowOptions.WFTcpPort, token = cumulus.WeatherFlowOptions.WFToken, dayshistory = cumulus.WeatherFlowOptions.WFDaysHist }; + { + deviceid = cumulus.WeatherFlowOptions.WFDeviceId, + tcpport = cumulus.WeatherFlowOptions.WFTcpPort, + token = cumulus.WeatherFlowOptions.WFToken, + dayshistory = cumulus.WeatherFlowOptions.WFDaysHist + }; var gw1000 = new JsonStationSettingsGw1000Conn() { diff --git a/CumulusMX/webtags.cs b/CumulusMX/webtags.cs index 1207f4df..5978be97 100644 --- a/CumulusMX/webtags.cs +++ b/CumulusMX/webtags.cs @@ -165,9 +165,9 @@ private double CheckTempUnit(double val, Dictionary tagParams) { var unit = tagParams.Get("unit").ToLower(); if (unit == "c") - return station.ConvertUserTempToC(val); + return ConvertUnits.UserTempToC(val); else if (unit == "f") - return station.ConvertUserTempToF(val); + return ConvertUnits.UserTempToF(val); } return val; } @@ -191,11 +191,11 @@ private double CheckPressUnit(double val, Dictionary tagParams) { var unit = tagParams.Get("unit").ToLower(); if (unit == "hpa" || unit == "mb") - return station.ConvertUserPressureToHPa(val); + return ConvertUnits.UserPressureToHPa(val); else if (unit == "kpa") - return station.ConvertUserPressureToHPa(val) / 10; + return ConvertUnits.UserPressureToHPa(val) / 10; else if (unit == "inhg") - return station.ConvertUserPressToIN(val); + return ConvertUnits.UserPressToIN(val); } return val; } @@ -206,9 +206,9 @@ private double CheckRainUnit(double val, Dictionary tagParams) { var unit = tagParams.Get("unit").ToLower(); if (unit == "mm") - return station.ConvertUserRainToMM(val); + return ConvertUnits.UserRainToMM(val); else if (unit == "in") - return station.ConvertUserRainToIN(val); + return ConvertUnits.UserRainToIN(val); } return val; } @@ -219,13 +219,13 @@ private double CheckWindUnit(double val, Dictionary tagParams) { var unit = tagParams.Get("unit").ToLower(); if (unit == "mph") - return station.ConvertUserWindToMPH(val); + return ConvertUnits.UserWindToMPH(val); else if (unit == "kph") - return station.ConvertUserWindToKPH(val); + return ConvertUnits.UserWindToKPH(val); else if (unit == "ms") - return station.ConvertUserWindToMS(val); + return ConvertUnits.UserWindToMS(val); else if (unit == "kt") - return station.ConvertUserWindToKnots(val); + return ConvertUnits.UserWindToKnots(val); } return val; } @@ -236,11 +236,11 @@ private double CheckWindRunUnit(double val, Dictionary tagParams { var unit = tagParams.Get("unit").ToLower(); if (unit == "mi") - return station.ConvertWindRunToMi(val); + return ConvertUnits.WindRunToMi(val); else if (unit == "km") - return station.ConvertWindRunToKm(val); + return ConvertUnits.WindRunToKm(val); else if (unit == "nm") - return station.ConvertWindRunToNm(val); + return ConvertUnits.WindRunToNm(val); } return val; } @@ -2301,12 +2301,12 @@ private string TagwindYm(Dictionary tagParams) private string TagYbeaufort(Dictionary tagParams) { - return "F" + station.Beaufort(station.HiLoYest.HighWind); + return "F" + ConvertUnits.Beaufort(station.HiLoYest.HighWind); } private string TagYbeaufortnumber(Dictionary tagParams) { - return station.Beaufort(station.HiLoYest.HighWind).ToString(); + return ConvertUnits.Beaufort(station.HiLoYest.HighWind).ToString(); } private string TagYbeaudesc(Dictionary tagParams) @@ -2475,12 +2475,12 @@ private string TagTwspeedH(Dictionary tagParams) return GetFormattedDateTime(station.AllTime.HighWind.Ts, "\\a\\t HH:mm o\\n dd MMMM yyyy", tagParams); } - private string TagwchillH(Dictionary tagParams) + private string TagwchillL(Dictionary tagParams) { return CheckRcDp(CheckTempUnit(station.AllTime.LowChill.Val, tagParams), tagParams, cumulus.TempDPlaces); } - private string TagTwchillH(Dictionary tagParams) + private string TagTwchillL(Dictionary tagParams) { return GetFormattedDateTime(station.AllTime.LowChill.Ts, "\\a\\t HH:mm o\\n dd MMMM yyyy", tagParams); } @@ -3273,6 +3273,19 @@ private string TagEcowittCameraUrl(Dictionary tagParams) } } + private string TagEcowittVideoUrl(Dictionary tagParams) + { + if (cumulus.StationType == StationTypes.GW1000 || cumulus.StationType == StationTypes.HttpEcowitt || cumulus.StationType == StationTypes.EcowittCloud) + { + return string.IsNullOrEmpty(station.GetEcowittVideoUrl()) ? string.Empty : station.EcowittVideoUrl; + } + else + { + return string.Empty; + } + } + + private string Tagtempunit(Dictionary tagParams) { return EncodeForWeb(cumulus.Units.TempText); @@ -3386,7 +3399,6 @@ private string TagLastRainTipIso(Dictionary tagParams) private string TagLastRainTip(Dictionary tagParams) { - string dtformat = tagParams.Get("format"); try { var lastTip = DateTime.Parse(station.LastRainTip); @@ -3667,7 +3679,7 @@ private string TagIsSunny(Dictionary tagParams) private string TagIsFreezing(Dictionary tagParams) { - return station.ConvertUserTempToC(station.OutdoorTemperature) < 0.09 ? "1" : "0"; + return ConvertUnits.UserTempToC(station.OutdoorTemperature) < 0.09 ? "1" : "0"; } private string TagIsRaining(Dictionary tagParams) @@ -5958,8 +5970,8 @@ public void InitialiseWebtags() { "TwspeedH", TagTwspeedH }, { "windrunH", TagwindrunH }, { "TwindrunH", TagTwindrunH }, - { "wchillH", TagwchillH }, - { "TwchillH", TagTwchillH }, + { "wchillL", TagwchillL }, + { "TwchillL", TagTwchillL }, { "rrateM", TagrrateM }, { "TrrateM", TagTrrateM }, { "rfallH", TagrfallH }, @@ -6028,6 +6040,7 @@ public void InitialiseWebtags() { "webcam", Tagwebcam }, { "webcamurl", Tagwebcamurl }, { "EcowittCameraUrl", TagEcowittCameraUrl }, + { "EcowittVideoUrl", TagEcowittVideoUrl }, { "tempunit", Tagtempunit }, { "tempunitnodeg", Tagtempunitnodeg }, { "tempunitnoenc", Tagtempunitnoenc }, diff --git a/Updates.txt b/Updates.txt index fadba150..033e4046 100644 --- a/Updates.txt +++ b/Updates.txt @@ -1,3 +1,46 @@ +3.28.0 - b3269 +—————————————— +New +- Adds the option to clear the latest error log +- Adds User Defined Alarms + - Trigger an alarm when any numeric or boolean web tag value exceeds or falls below a set value + - Boolean web tags evaluate to 0 or 1 (false, true), so are treated as numeric +- You can now change the built-in alarm descriptions in the Locale Strings settings +- Adds a new web tag <#EcowittVideoUrl> to get the URL of the latest Ecowitt camera timelapse video + +Changed +- Warning message from WLL station about spurious broadcast messages changed to a Debug message +- All time low wind chill web tags were miss named wchillH and TwchillH. They are now wchillL and TwchillL + - The default web site page record.htm has been changed to reflect this + - As has the websitedataT.json file +- Calibration and Limit values are now displayed and set in your native units +- NOAA reports now produce an error rather than skipping over if a duplicate entry is detected in the dayfile +- Reload dayfile now produces an error rather than skipping over if a duplicate entry is detected in the dayfile +- The default path in the sample cumulusmx.service file has been changed to /opt/CumulusMX +- Upload.php amended to change the maximum permitted clock difference between MX and the remote server to 20 seconds (was 10) +- The MQTT config files are now only read at start-up or when the MQTT Settings are saved +- The MQTT settings have been removed from Internet Settings to their own page +*** BREAKING CHANGE *** +- The MQTT interval data sending has changed. Previously all topics sent at the same fixed interval. Now you can specify an interval per topic in the MQTT config file + If you are using MQTT interval topics, then please the ReadMe.txt file in the /mqtt folder for details of the changes you need to make + +Fixed +- Add missing New Record and FTP alarm info to the dashboard data stream +- Some AirLink wl.com API calls not using the correct API details when configured as Standalone +- Indoor Temperature and Humidity spike removal not working +- Program Setting 'Remove space character from date separators (if present)' now applies to all output +- The Ecowitt API MAC address field was not allowed to be blank in the Wizard or station config +- Wind Gust values not being recorded as high values with moderate spike values set and wind speed in mph or knots + +Package Updates +- MailKit/MimeKit +- MySqlConnector +- ServiceStack.Text +- SQLite +- MQTTnet +- FluentFTP (customised CMX version until new a build is released) + + 3.27.1 - b3263 —————————————— New @@ -45,7 +88,7 @@ New - It grabs the data from the Ecowitt cloud servers. This data is updated once a minute and is slightly less rich than the locally available API data. - This station can also be used as a source of Extra Sensor data for your primary station - It also makes available the URL of the latest camera on the Ecowitt cloud server via the new web tag <#EcowittCameraUrl> - - You can use the tag in the URL field of HTTP Files to download the latest image + - You can use the tag "" in the URL field of HTTP Files to download the latest image - Adds a new station type of Davis Cloud - It grabs the data from the Davis WeatherLink cloud servers. The data is updated according to your subscription model - Pro+ = 1 minute updates