SemlerPDX icon

Serial Monitor of Arduino from C# inline function for VoiceAttack

SemlerPDX | PRO | 05/24/22 04:55:08 AM UTC (Edited) | 0 ⭐ | 1322 👁️ | Never ⏰ | []
C# |

13.24 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.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