//AVCS SENS - AVCS-DHT1 External Sensor Temperature Data Monitoring Function v4
// - Parses new External DHT11 data from Arduino every 30 seconds
// by SemlerPDX Mar/May2022
// VETERANS-GAMING.COM
//#define DEBUG //DEV DEBUGGING - comment/uncomment to disable/enable debug output
using System;
using System.IO.Ports;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
public class VAInline
{
double MonitorTimerDelay = 2000; //in milliseconds (default 2000 == 2 seconds)
public void ClearSensorVariables()
{
VA.SetDecimal("AVCS_SENS_TempDHTc", null);
VA.SetDecimal("AVCS_SENS_TempDHTh", null);
VA.SetDecimal("AVCS_SENS_TempDHTf", null);
VA.SetDecimal("AVCS_SENS_TempDHTi", null);
}
public void ClearMonitorVariables()
{
ClearSensorVariables();
VA.SetInt("AVCS_SENS_IntervalDHT1", null);
VA.SetText("AVCS_SENS_ComportDHT1", null);
VA.SetBoolean("AVCS_SENS_MonitoringDHT1", null);
VA.SetBoolean("AVCS_SENS_SensorTestDHT1", null);
}
public void SensorMonitoringEnd()
{
ClearMonitorVariables();
VA.WriteToLog("External AVCS-DHT1 Sensor Monitor has been terminated...", "black");
}
public void SensorTestFailure()
{
ClearMonitorVariables();
VA.WriteToLog("AVCS-DHT1 Sensor Identification Test FAILURE!", "red");
VA.WriteToLog("Please check USB connection of AVCS-DHT1 Sensor. See user guide for more information.", "red");
VA.SetText("AVCS_SENS_Test_ReturnTTS", "Test failed. Please check device or settings.");
}
public void SensorIdentifyFailure()
{
ClearMonitorVariables();
VA.WriteToLog("External AVCS-DHT1 Sensor comport not found...", "black");
VA.WriteToLog("Diagnostic & indoor weather commands will be unavailable", "black");
}
private void WriteToLog_Long(string longString, string colorString)
{
StringBuilder sb = new StringBuilder();
string[] longStringSegments = longString.Split(new string[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
//Write each new line of log data, break up any longer than approximate min-width of VA window (~91) to new lines
for (int a = 0; a < longStringSegments.Length; a++)
{
if (longStringSegments[a].Length > 91)
{
sb.Append(longStringSegments[a].ToString());
while (sb.Length > 91)
{
try
{
VA.WriteToLog(sb.ToString(0, 91), colorString);
sb.Remove(0, 91);
}
catch
{
//ignore
}
finally
{
if (sb.Length <= 91)
VA.WriteToLog(sb.ToString(), colorString);
}
}
}
else
{
//Lines already less than 91 characters
VA.WriteToLog(longStringSegments[a], colorString);
}
}
}
public decimal TTS_GetRoundedDecimal(string thisStringDec, int decimalPlaces)
{
//For Text-To-Speech brevity, return decimal that does not end in .00'
decimal thisDecimal = Decimal.Round(Convert.ToDecimal(thisStringDec), decimalPlaces);
decimal truncatedDecimal = Decimal.Truncate(thisDecimal);
if (truncatedDecimal != thisDecimal)
return thisDecimal;
return truncatedDecimal;
}
private string GetArduinoSerialData(string PortDHT1)
{
System.IO.Ports.SerialPort SerialPortDHT1 = new System.IO.Ports.SerialPort();
bool debugging = false;
if (VA.GetBoolean("AVCS_SENS_DebugArduino") == true)
debugging = true;
string incoming = "";
string dataBuild = "";
bool dataComplete = false;
int serialReadTimeouts = 0;
int timeoutsMax = 4;
int dataChars = 1;
byte[] inBuffer = new byte[1];
SerialPortDHT1.PortName = PortDHT1;
SerialPortDHT1.BaudRate = 9600;
SerialPortDHT1.DataBits = 8;
SerialPortDHT1.Parity = Parity.None;
SerialPortDHT1.StopBits = StopBits.One;
SerialPortDHT1.Handshake = Handshake.None;
SerialPortDHT1.Encoding = System.Text.Encoding.Default;
SerialPortDHT1.ReadTimeout = 250;
if (SerialPortDHT1.IsOpen)
{
SerialPortDHT1.Close();
while (SerialPortDHT1.IsOpen)
Thread.Sleep(150);
Thread.Sleep(2000); //Restart Delay for Arduino Sketch?
}
try
{
SerialPortDHT1.Open();
Thread.Sleep(100);
}
catch (Exception ex)
{
dataComplete = true;
dataBuild = "nothing";
if (debugging)
WriteToLog_Long("AVCS Error: Serial Port Open() ended on exception" +
Environment.NewLine + "Error Details:" +
Environment.NewLine + ex.ToString(), "red");
}
while (dataComplete != true)
{
try
{
SerialPortDHT1.Read(inBuffer, 0, 1);
incoming = Encoding.ASCII.GetString(inBuffer, 0, inBuffer.Length);
if (String.IsNullOrEmpty(incoming))
{
incoming = "nothing";
}
else
{
if (String.IsNullOrEmpty(dataBuild))
{
if (incoming == "[")
dataBuild += incoming;
}
else
{
dataChars++;
dataBuild += incoming;
if (incoming == "]")
dataComplete = true;
}
if ((dataChars >= 39) && (dataComplete != true))
serialReadTimeouts = timeoutsMax;
}
}
catch (TimeoutException e)
{
serialReadTimeouts += 1;
if (debugging)
VA.WriteToLog("AVCS Error: Serial Port read timed out.", "red");
}
finally
{
if ((serialReadTimeouts > timeoutsMax) && (dataComplete != true))
{
dataComplete = true;
dataBuild = "nothing";
if (debugging)
VA.WriteToLog("AVCS Error: Serial Port data read ended on timeout", "red");
}
}
}
SerialPortDHT1.Dispose();
return dataBuild;
}
private string GetArduinoPortName(string portRegExCheck)
{
string portNameDHT = "";
string receivedData = "";
string[] ports = SerialPort.GetPortNames();
int serialPortAttemptsMax = 8;
if (ports.Length > 0)
serialPortAttemptsMax = ports.Length * serialPortAttemptsMax;
if ((VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true) || (ports.Length > 0 && ports.Length <= 3))
serialPortAttemptsMax *= 2;
for (int serialPortAttempts = 0; serialPortAttempts <= serialPortAttemptsMax; serialPortAttempts++)
{
foreach (string port in ports)
{
try
{
receivedData = GetArduinoSerialData(port);
}
catch
{
receivedData = "nothing";
}
finally
{
if (Regex.IsMatch(receivedData, portRegExCheck))
portNameDHT = port;
}
if (portNameDHT != "")
break;
}
if (portNameDHT != "")
break;
}
if ((VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true) && (portNameDHT != ""))
{
VA.WriteToLog("AVCS-DHT1 Data: " + receivedData, "blue");
VA.WriteToLog("AVCS-DHT1 Sensor Test has succeeded!", "green");
VA.SetText("AVCS_SENS_Test_ReturnTTS", "Test succeeded.");
}
return portNameDHT;
}
private void MonitorTimer(double MonitorTimerDelay)
{
VA.WriteToLog("AVCS-DHT1 Sensor Monitor is now running...", "black");
VA.SetBoolean("AVCS_SENS_TimerWorkingDHT1", null);
VA.SetInt("AVCS_SENS_IntervalDHT1", null);
System.Timers.Timer t = new System.Timers.Timer(MonitorTimerDelay);
t.Elapsed += MonitorTimerElapsed;
t.Start();
}
private void MonitorTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (VA.GetBoolean("AVCS_SENS_TimerWorkingDHT1") != true)
{
VA.SetBoolean("AVCS_SENS_TimerWorkingDHT1", true);
bool debugging = false;
if (VA.GetBoolean("AVCS_SENS_DebugArduino") == true)
debugging = true;
if (VA.GetBoolean("AVCS_SENS_MonitoringDHT1") != true)
{
SensorMonitoringEnd();
(sender as System.Timers.Timer).Stop();
}
else
{
// Serial Data in format: [AVCS,-cc.cc,hh.hh,-ff.ff,-xx.xx,DHT1] *negatives possible yet highly unlikely
string dataRegEx = @"^\[AVCS\,\-?\d\d\.\d\d\,\d\d\.\d\d\,\-?\d\d\.\d\d\,\-?\d\d\.\d\d\,DHT1\]$";
string comPort = "";
string receivedData = "";
int ArduinoCheckDelay = 15; //in multiples of MonitorTimerDelay (default 15*2000 == 30 seconds)
int intervalDHT = Convert.ToInt32(VA.ParseTokens("{INT:AVCS_SENS_IntervalDHT1:" +
ArduinoCheckDelay.ToString() + "}"));
intervalDHT++;
if (intervalDHT > ArduinoCheckDelay)
intervalDHT = 0;
VA.SetInt("AVCS_SENS_IntervalDHT1", intervalDHT);
if (debugging)
VA.WriteToLog("INTERVAL: " + intervalDHT.ToString(), "purple");
if ((intervalDHT == 0) || (VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true))
{
if (String.IsNullOrEmpty(VA.GetText("AVCS_SENS_ComportDHT1")))
{
ClearSensorVariables();
comPort = GetArduinoPortName(dataRegEx);
if (debugging)
VA.WriteToLog("COMPORT = " + comPort, "pink");
if (comPort.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
{
VA.SetText("AVCS_SENS_ComportDHT1", comPort);
}
else
{
comPort = "";
if (VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true)
{
SensorTestFailure();
}
else
{
SensorIdentifyFailure();
}
}
}
else
{
comPort = VA.GetText("AVCS_SENS_ComportDHT1");
}
if (VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true)
VA.SetBoolean("AVCS_SENS_SensorTestDHT1", null);
//Continuing Operations Check - if not monitoring other systems, or failures above:
int checkSystems = 0;
if (VA.GetBoolean("AVCS_OWM_Monitor_Startup") != true)
{
if (VA.GetBoolean("AVCS_OWM_Monitoring") != true)
checkSystems++;
}
if (VA.GetBoolean("AVCS_SENS_Monitor_Startup") != true)
{
if (VA.GetBoolean("AVCS_SENS_Monitoring") != true)
checkSystems++;
}
if ((VA.GetBoolean("AVCS_SENS_MonitoringDHT1") != true) || (checkSystems == 2))
comPort = "";
if (comPort != "")
{
receivedData = GetArduinoSerialData(comPort);
if (Regex.IsMatch(receivedData, dataRegEx))
{
if (debugging)
VA.WriteToLog(receivedData.ToString(), "blue");
string[] receivedDataArray = receivedData.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
VA.SetDecimal("AVCS_SENS_TempDHTc", TTS_GetRoundedDecimal(receivedDataArray[1], 2));
VA.SetDecimal("AVCS_SENS_TempDHTh", TTS_GetRoundedDecimal(receivedDataArray[2], 2));
VA.SetDecimal("AVCS_SENS_TempDHTf", TTS_GetRoundedDecimal(receivedDataArray[3], 2));
VA.SetDecimal("AVCS_SENS_TempDHTi", TTS_GetRoundedDecimal(receivedDataArray[4], 0));
}
else
{
//When a single read of previously good ComPort fails, null the ComPort var for one last try on next interval
if (debugging)
VA.WriteToLog("RegEx was not match - circling back to try again","pink");
VA.SetText("AVCS_SENS_ComportDHT1", null);
VA.SetInt("AVCS_SENS_IntervalDHT1", ArduinoCheckDelay); //bypass 30 second wait for last try before quitting
}
}
else
{
SensorMonitoringEnd();
(sender as System.Timers.Timer).Stop();
}
}
}
if (VA.GetBoolean("AVCS_DHT1_Monitor_Startup") == true)
VA.SetBoolean("AVCS_DHT1_Monitor_Startup", null);
VA.SetBoolean("AVCS_SENS_TimerWorkingDHT1", false);
}
}
public void main()
{
//DEV DEBUGGING -- Sets SENS_MONITORING to true to simulate systems running and keep this loop active
#if (DEBUG)
VA.SetBoolean("AVCS_SENS_Monitoring", true); // (means AIDA64 monitoring is on, allows this test to loop)
VA.SetBoolean("AVCS_SENS_DebugArduino", true);
#endif
if (VA.GetBoolean("AVCS_SENS_MonitoringDHT1") != true)
{
#if (DEBUG)
VA.ClearLog();
#endif
VA.SetBoolean("AVCS_SENS_MonitoringDHT1", true);
MonitorTimer(MonitorTimerDelay);
}
#if (DEBUG)
else //DEV DEBUGGING ELSE -- for TEST RUN Toggle On/Off in editor
{
VA.WriteToLog("DEV DISABLE BOOLS - RESET TEST", "grey");
VA.SetBoolean("AVCS_SENS_Monitoring", false);
VA.SetBoolean("AVCS_SENS_MonitoringDHT1", false);
}
#endif
}
}
Comments