SemlerPDX icon

AVCS SENS DHT1 MAIN-v4 Inline Function in C# for VoiceAttack & Arduino

SemlerPDX | PRO | 08/15/22 05:03:07 PM UTC (Edited) | 0 ⭐ | 1508 👁️ | Never ⏰ | []
C# |

12.55 KB

|

None

|

0 👍

/

0 👎

//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.Linq;
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 = 100;
        if (SerialPortDHT1 != null)
        {
            if (SerialPortDHT1.IsOpen)
            {
                SerialPortDHT1.Close();
                while (SerialPortDHT1.IsOpen)
                    Thread.Sleep(100);
                //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().Distinct().ToArray();
        int serialPortAttemptsMax = 8;
        if (ports.Length > 0)
            serialPortAttemptsMax = ports.Length * serialPortAttemptsMax;
        
        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 bool ContinuingSystemsOperationEnded()
    {
        //Continuing Operations Check - if not monitoring other systems, end this monitor timer
        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 (checkSystems == 2)
            return true;
        
        return false;
    }
    
    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("DHT INTERVAL: " + intervalDHT.ToString(), "purple");
                
                if (VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true)
                    VA.SetText("AVCS_SENS_ComportDHT1", null);
                
                if ((intervalDHT == 0) || (VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true))
                {
                    if (String.IsNullOrEmpty(VA.GetText("AVCS_SENS_ComportDHT1")))
                    {
                        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");
                    }
                    
                    //Clear Testing Variable after test run (if true)
                    if (VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true)
                        VA.SetBoolean("AVCS_SENS_SensorTestDHT1", null);
                    
                    //Continuing Operation Check - exit if OWM and AIDA64 monitors not running
                    if ((VA.GetBoolean("AVCS_SENS_MonitoringDHT1") != true) || (ContinuingSystemsOperationEnded()))
                        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], 0));
                            VA.SetDecimal("AVCS_SENS_TempDHTf", TTS_GetRoundedDecimal(receivedDataArray[3], 1));
                            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: " + receivedData,"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();
                    }
                }
            }
            //Clear Startup Variable after first run (if true)
            if (VA.GetBoolean("AVCS_DHT1_Monitor_Startup") == true)
                VA.SetBoolean("AVCS_DHT1_Monitor_Startup", null);
            //Final Continuing Operation Check - exit if OWM and AIDA64 monitors not running
            if (ContinuingSystemsOperationEnded())
                VA.SetBoolean("AVCS_SENS_MonitoringDHT1", false);
            
            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
            ClearSensorVariables();
            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);
            VA.SetBoolean("AVCS_SENS_DebugArduino", false);
        }
        #endif
    }
}

Comments