Advertisement
SemlerPDX

Serial Monitor of Arduino from C# inline function for VoiceAttack

May 23rd, 2022 (edited)
893
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 13.24 KB | None | 0 0
  1. //AVCS SENS - AVCS-DHT1 External Sensor Temperature Data Monitoring Function v4
  2. // - Parses new External DHT11 data from Arduino every 30 seconds
  3. // by SemlerPDX Mar/May2022
  4. // VETERANS-GAMING.COM
  5.  
  6. //#define DEBUG  //DEV DEBUGGING - comment/uncomment to disable/enable debug output
  7.  
  8. using System;
  9. using System.IO.Ports;
  10. using System.Text;
  11. using System.Text.RegularExpressions;
  12. using System.Threading;
  13.  
  14. public class VAInline
  15. {
  16.   double MonitorTimerDelay = 2000; //in milliseconds (default 2000 == 2 seconds)
  17.  
  18.   public void ClearSensorVariables()
  19.   {
  20.     VA.SetDecimal("AVCS_SENS_TempDHTc", null);
  21.     VA.SetDecimal("AVCS_SENS_TempDHTh", null);
  22.     VA.SetDecimal("AVCS_SENS_TempDHTf", null);
  23.     VA.SetDecimal("AVCS_SENS_TempDHTi", null);
  24.   }
  25.  
  26.   public void ClearMonitorVariables()
  27.   {
  28.     ClearSensorVariables();
  29.     VA.SetInt("AVCS_SENS_IntervalDHT1", null);
  30.     VA.SetText("AVCS_SENS_ComportDHT1", null);
  31.     VA.SetBoolean("AVCS_SENS_MonitoringDHT1", null);
  32.     VA.SetBoolean("AVCS_SENS_SensorTestDHT1", null);
  33.   }
  34.  
  35.   public void SensorMonitoringEnd()
  36.   {
  37.     ClearMonitorVariables();
  38.     VA.WriteToLog("External AVCS-DHT1 Sensor Monitor has been terminated...", "black");
  39.   }
  40.  
  41.   public void SensorTestFailure()
  42.   {
  43.     ClearMonitorVariables();
  44.     VA.WriteToLog("AVCS-DHT1 Sensor Identification Test FAILURE!", "red");
  45.     VA.WriteToLog("Please check USB connection of AVCS-DHT1 Sensor. See user guide for more information.", "red");
  46.     VA.SetText("AVCS_SENS_Test_ReturnTTS", "Test failed. Please check device or settings.");
  47.   }
  48.  
  49.   public void SensorIdentifyFailure()
  50.   {
  51.     ClearMonitorVariables();
  52.     VA.WriteToLog("External AVCS-DHT1 Sensor comport not found...", "black");
  53.     VA.WriteToLog("Diagnostic & indoor weather commands will be unavailable", "black");
  54.   }
  55.  
  56.   private void WriteToLog_Long(string longString, string colorString)
  57.   {
  58.     StringBuilder sb = new StringBuilder();
  59.     string[] longStringSegments = longString.Split(new string[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
  60.    
  61.     //Write each new line of log data, break up any longer than approximate min-width of VA window (~91) to new lines
  62.     for (int a = 0; a < longStringSegments.Length; a++)
  63.     {
  64.       if (longStringSegments[a].Length > 91)
  65.       {
  66.         sb.Append(longStringSegments[a].ToString());
  67.         while (sb.Length > 91)
  68.         {
  69.           try
  70.           {
  71.             VA.WriteToLog(sb.ToString(0, 91), colorString);
  72.             sb.Remove(0, 91);
  73.           }
  74.           catch
  75.           {
  76.             //ignore
  77.           }
  78.           finally
  79.           {
  80.             if (sb.Length <= 91)
  81.               VA.WriteToLog(sb.ToString(), colorString);
  82.           }
  83.         }
  84.       }
  85.       else
  86.       {
  87.         //Lines already less than 91 characters
  88.         VA.WriteToLog(longStringSegments[a], colorString);
  89.       }
  90.     }
  91.   }
  92.  
  93.   public decimal TTS_GetRoundedDecimal(string thisStringDec, int decimalPlaces)
  94.   {
  95.     //For Text-To-Speech brevity, return decimal that does not end in .00'
  96.     decimal thisDecimal = Decimal.Round(Convert.ToDecimal(thisStringDec), decimalPlaces);
  97.     decimal truncatedDecimal = Decimal.Truncate(thisDecimal);
  98.     if (truncatedDecimal != thisDecimal)
  99.       return thisDecimal;
  100.    
  101.     return truncatedDecimal;
  102.   }
  103.  
  104.   private string GetArduinoSerialData(string PortDHT1)
  105.   {
  106.     System.IO.Ports.SerialPort SerialPortDHT1 = new System.IO.Ports.SerialPort();
  107.     bool debugging = false;
  108.     if (VA.GetBoolean("AVCS_SENS_DebugArduino") == true)
  109.       debugging = true;
  110.    
  111.     string incoming = "";
  112.     string dataBuild = "";
  113.     bool dataComplete = false;
  114.     int serialReadTimeouts = 0;
  115.     int timeoutsMax = 4;
  116.     int dataChars = 1;
  117.     byte[] inBuffer = new byte[1];
  118.    
  119.     SerialPortDHT1.PortName = PortDHT1;
  120.     SerialPortDHT1.BaudRate = 9600;
  121.     SerialPortDHT1.DataBits = 8;
  122.     SerialPortDHT1.Parity = Parity.None;
  123.     SerialPortDHT1.StopBits = StopBits.One;
  124.     SerialPortDHT1.Handshake = Handshake.None;
  125.     SerialPortDHT1.Encoding = System.Text.Encoding.Default;
  126.     SerialPortDHT1.ReadTimeout = 250;
  127.     if (SerialPortDHT1.IsOpen)
  128.     {
  129.       SerialPortDHT1.Close();
  130.       while (SerialPortDHT1.IsOpen)
  131.         Thread.Sleep(150);
  132.       Thread.Sleep(2000); //Restart Delay for Arduino Sketch?
  133.     }
  134.    
  135.     try
  136.     {
  137.       SerialPortDHT1.Open();
  138.       Thread.Sleep(100);
  139.     }
  140.     catch (Exception ex)
  141.     {
  142.       dataComplete = true;
  143.       dataBuild = "nothing";
  144.       if (debugging)
  145.         WriteToLog_Long("AVCS Error: Serial Port Open() ended on exception" +
  146.                   Environment.NewLine + "Error Details:" +
  147.                   Environment.NewLine + ex.ToString(), "red");
  148.     }
  149.    
  150.     while (dataComplete != true)
  151.     {
  152.       try
  153.       {
  154.         SerialPortDHT1.Read(inBuffer, 0, 1);
  155.         incoming = Encoding.ASCII.GetString(inBuffer, 0, inBuffer.Length);
  156.         if (String.IsNullOrEmpty(incoming))
  157.         {
  158.           incoming = "nothing";
  159.         }
  160.         else
  161.         {
  162.           if (String.IsNullOrEmpty(dataBuild))
  163.           {
  164.             if (incoming == "[")
  165.               dataBuild += incoming;
  166.           }
  167.           else
  168.           {
  169.             dataChars++;
  170.             dataBuild += incoming;
  171.             if (incoming == "]")
  172.               dataComplete = true;
  173.           }
  174.           if ((dataChars >= 39) && (dataComplete != true))
  175.             serialReadTimeouts = timeoutsMax;
  176.         }
  177.       }
  178.       catch (TimeoutException e)
  179.       {
  180.         serialReadTimeouts += 1;
  181.         if (debugging)
  182.           VA.WriteToLog("AVCS Error: Serial Port read timed out.", "red");
  183.       }
  184.       finally
  185.       {
  186.         if ((serialReadTimeouts > timeoutsMax) && (dataComplete != true))
  187.         {
  188.           dataComplete = true;
  189.           dataBuild = "nothing";
  190.           if (debugging)
  191.             VA.WriteToLog("AVCS Error: Serial Port data read ended on timeout", "red");
  192.         }
  193.       }
  194.     }
  195.    
  196.     SerialPortDHT1.Dispose();
  197.     return dataBuild;
  198.   }
  199.  
  200.   private string GetArduinoPortName(string portRegExCheck)
  201.   {
  202.     string portNameDHT = "";
  203.     string receivedData = "";
  204.     string[] ports = SerialPort.GetPortNames();
  205.     int serialPortAttemptsMax = 8;
  206.     if (ports.Length > 0)
  207.       serialPortAttemptsMax = ports.Length * serialPortAttemptsMax;
  208.     if ((VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true) || (ports.Length > 0 && ports.Length <= 3))
  209.       serialPortAttemptsMax *= 2;
  210.     for (int serialPortAttempts = 0; serialPortAttempts <= serialPortAttemptsMax; serialPortAttempts++)
  211.     {
  212.       foreach (string port in ports)
  213.       {
  214.         try
  215.         {
  216.           receivedData = GetArduinoSerialData(port);
  217.         }
  218.         catch
  219.         {
  220.           receivedData = "nothing";
  221.         }
  222.         finally
  223.         {
  224.           if (Regex.IsMatch(receivedData, portRegExCheck))
  225.             portNameDHT = port;
  226.         }
  227.         if (portNameDHT != "")
  228.           break;
  229.       }
  230.       if (portNameDHT != "")
  231.         break;
  232.     }
  233.    
  234.     if ((VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true) && (portNameDHT != ""))
  235.     {
  236.       VA.WriteToLog("AVCS-DHT1 Data: " + receivedData, "blue");
  237.       VA.WriteToLog("AVCS-DHT1 Sensor Test has succeeded!", "green");
  238.       VA.SetText("AVCS_SENS_Test_ReturnTTS", "Test succeeded.");
  239.     }
  240.    
  241.     return portNameDHT;
  242.   }
  243.  
  244.   private void MonitorTimer(double MonitorTimerDelay)
  245.   {
  246.     VA.WriteToLog("AVCS-DHT1 Sensor Monitor is now running...", "black");
  247.     VA.SetBoolean("AVCS_SENS_TimerWorkingDHT1", null);
  248.     VA.SetInt("AVCS_SENS_IntervalDHT1", null);
  249.     System.Timers.Timer t = new System.Timers.Timer(MonitorTimerDelay);
  250.     t.Elapsed += MonitorTimerElapsed;
  251.     t.Start();
  252.   }
  253.  
  254.   private void MonitorTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
  255.   {
  256.     if (VA.GetBoolean("AVCS_SENS_TimerWorkingDHT1") != true)
  257.     {
  258.       VA.SetBoolean("AVCS_SENS_TimerWorkingDHT1", true);
  259.       bool debugging = false;
  260.       if (VA.GetBoolean("AVCS_SENS_DebugArduino") == true)
  261.         debugging = true;
  262.      
  263.       if (VA.GetBoolean("AVCS_SENS_MonitoringDHT1") != true)
  264.       {
  265.         SensorMonitoringEnd();
  266.         (sender as System.Timers.Timer).Stop();
  267.       }
  268.       else
  269.       {
  270.         // Serial Data in format: [AVCS,-cc.cc,hh.hh,-ff.ff,-xx.xx,DHT1]  *negatives possible yet highly unlikely
  271.         string dataRegEx = @"^\[AVCS\,\-?\d\d\.\d\d\,\d\d\.\d\d\,\-?\d\d\.\d\d\,\-?\d\d\.\d\d\,DHT1\]$";
  272.         string comPort = "";
  273.         string receivedData = "";
  274.         int ArduinoCheckDelay = 15; //in multiples of MonitorTimerDelay (default 15*2000 == 30 seconds)
  275.         int intervalDHT = Convert.ToInt32(VA.ParseTokens("{INT:AVCS_SENS_IntervalDHT1:" +
  276.                                   ArduinoCheckDelay.ToString() + "}"));
  277.         intervalDHT++;
  278.         if (intervalDHT > ArduinoCheckDelay)
  279.           intervalDHT = 0;
  280.         VA.SetInt("AVCS_SENS_IntervalDHT1", intervalDHT);
  281.        
  282.         if (debugging)
  283.           VA.WriteToLog("INTERVAL: " + intervalDHT.ToString(), "purple");
  284.        
  285.         if ((intervalDHT == 0) || (VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true))
  286.         {
  287.           if (String.IsNullOrEmpty(VA.GetText("AVCS_SENS_ComportDHT1")))
  288.           {
  289.             ClearSensorVariables();
  290.             comPort = GetArduinoPortName(dataRegEx);
  291.             if (debugging)
  292.               VA.WriteToLog("COMPORT = " + comPort, "pink");
  293.             if (comPort.StartsWith("COM", StringComparison.OrdinalIgnoreCase))
  294.             {
  295.               VA.SetText("AVCS_SENS_ComportDHT1", comPort);
  296.             }
  297.             else
  298.             {
  299.               comPort = "";
  300.               if (VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true)
  301.               {
  302.                 SensorTestFailure();
  303.               }
  304.               else
  305.               {
  306.                 SensorIdentifyFailure();
  307.               }
  308.             }
  309.           }
  310.           else
  311.           {
  312.             comPort = VA.GetText("AVCS_SENS_ComportDHT1");
  313.           }
  314.          
  315.           if (VA.GetBoolean("AVCS_SENS_SensorTestDHT1") == true)
  316.             VA.SetBoolean("AVCS_SENS_SensorTestDHT1", null);
  317.          
  318.          
  319.           //Continuing Operations Check - if not monitoring other systems, or failures above:
  320.           int checkSystems = 0;
  321.           if (VA.GetBoolean("AVCS_OWM_Monitor_Startup") != true)
  322.           {
  323.             if (VA.GetBoolean("AVCS_OWM_Monitoring") != true)
  324.               checkSystems++;
  325.           }
  326.           if (VA.GetBoolean("AVCS_SENS_Monitor_Startup") != true)
  327.           {
  328.             if (VA.GetBoolean("AVCS_SENS_Monitoring") != true)
  329.               checkSystems++;
  330.           }
  331.           if ((VA.GetBoolean("AVCS_SENS_MonitoringDHT1") != true) || (checkSystems == 2))
  332.             comPort = "";
  333.          
  334.           if (comPort != "")
  335.           {
  336.             receivedData = GetArduinoSerialData(comPort);
  337.             if (Regex.IsMatch(receivedData, dataRegEx))
  338.             {
  339.               if (debugging)
  340.                 VA.WriteToLog(receivedData.ToString(), "blue");
  341.              
  342.               string[] receivedDataArray = receivedData.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
  343.               VA.SetDecimal("AVCS_SENS_TempDHTc", TTS_GetRoundedDecimal(receivedDataArray[1], 2));
  344.               VA.SetDecimal("AVCS_SENS_TempDHTh", TTS_GetRoundedDecimal(receivedDataArray[2], 2));
  345.               VA.SetDecimal("AVCS_SENS_TempDHTf", TTS_GetRoundedDecimal(receivedDataArray[3], 2));
  346.               VA.SetDecimal("AVCS_SENS_TempDHTi", TTS_GetRoundedDecimal(receivedDataArray[4], 0));
  347.             }
  348.             else
  349.             {
  350.               //When a single read of previously good ComPort fails, null the ComPort var for one last try on next interval
  351.               if (debugging)
  352.                 VA.WriteToLog("RegEx was not match - circling back to try again","pink");
  353.              
  354.               VA.SetText("AVCS_SENS_ComportDHT1", null);
  355.               VA.SetInt("AVCS_SENS_IntervalDHT1", ArduinoCheckDelay); //bypass 30 second wait for last try before quitting
  356.             }
  357.           }
  358.           else
  359.           {
  360.             SensorMonitoringEnd();
  361.             (sender as System.Timers.Timer).Stop();
  362.           }
  363.         }
  364.       }
  365.      
  366.       if (VA.GetBoolean("AVCS_DHT1_Monitor_Startup") == true)
  367.         VA.SetBoolean("AVCS_DHT1_Monitor_Startup", null);
  368.      
  369.       VA.SetBoolean("AVCS_SENS_TimerWorkingDHT1", false);
  370.     }
  371.   }
  372.  
  373.   public void main()
  374.   {
  375.     //DEV DEBUGGING -- Sets SENS_MONITORING to true to simulate systems running and keep this loop active
  376.     #if (DEBUG)
  377.       VA.SetBoolean("AVCS_SENS_Monitoring", true); // (means AIDA64 monitoring is on, allows this test to loop)
  378.       VA.SetBoolean("AVCS_SENS_DebugArduino", true);
  379.     #endif
  380.    
  381.     if (VA.GetBoolean("AVCS_SENS_MonitoringDHT1") != true)
  382.     {
  383.       #if (DEBUG)
  384.         VA.ClearLog();
  385.       #endif
  386.      
  387.       VA.SetBoolean("AVCS_SENS_MonitoringDHT1", true);
  388.       MonitorTimer(MonitorTimerDelay);
  389.     }
  390.     #if (DEBUG)
  391.     else //DEV DEBUGGING ELSE -- for TEST RUN Toggle On/Off in editor
  392.     {
  393.       VA.WriteToLog("DEV DISABLE BOOLS - RESET TEST", "grey");
  394.       VA.SetBoolean("AVCS_SENS_Monitoring", false);
  395.       VA.SetBoolean("AVCS_SENS_MonitoringDHT1", false);
  396.     }
  397.     #endif
  398.   }
  399. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement