Ejemplo n.º 1
0
        public override void DoWork(I2C thisSensor)
        {
            I2cSensordata thisReading = new I2cSensordata();

            Sup.LogTraceInfoMessage($"I2cSensorDevice {SensorUsed}: DoWork routine entry");

            try
            {
                lock ( Response )
                {
                    thisConnect.Write(SHT31SingleShotCommand);
                    Response = thisConnect.Read(6);
                }

                // For debugging, normally not on
                Sup.LogTraceInfoMessage($"I2cSensorDevice {SensorUsed} data read: {Response[ 0 ]}; {Response[ 1 ]}; {Response[ 2 ]}; {Response[ 3 ]}; {Response[ 4 ]}; {Response[ 5 ]}; "); // {Response[6]}; {Response[7]};

                thisReading.Humidity     = 100 * (double)(Response[3] * 0x100 + Response[4]) / 65535;                                                                                       // BitConverter.ToUInt16(Response, 3) / 65535;
                thisReading.TemperatureF = -49 + 315 * (double)(Response[0] * 0x100 + Response[1]) / 65535;                                                                                 // Must be in Fahrenheit for the Davis simulation
                thisReading.TemperatureC = -45 + 175 * (double)(Response[0] * 0x100 + Response[1]) / 65535;                                                                                 // This is the same in Celsius

                thisSensor.ObservationList.Add(thisReading);
            }
            catch (Exception e)
            {
                Sup.LogTraceWarningMessage($"I2cSensorDevice Exception {SensorUsed}:...{e.Message}");
            }

            return;
        }
Ejemplo n.º 2
0
        public void SetMinuteValuesFromObservations()
        {
            if (Sensor.Valid)
            {
                lock ( MinuteValues )
                {
                    Sup.LogTraceInfoMessage($"SetMinuteValuesFromObservations: Creating minutevalues as average of the 10 second observations... {SensorUsed}");

                    if (Program.CUSensorsSwitch.TraceInfo)
                    {
                        int i = 0;
                        foreach (PMSensordata entry in ObservationList)
                        {
                            Sup.LogTraceInfoMessage($"Observationlist data {i++}: {entry.Pm1_atm:F1}; {entry.Pm25_atm:F1}; {entry.Pm10_atm:F1};");
                        }
                    }

                    MinuteValues.Pm1_atm  = ObservationList.Select(x => x.Pm1_atm).Average();
                    MinuteValues.Pm25_atm = ObservationList.Select(x => x.Pm25_atm).Average();
                    MinuteValues.Pm10_atm = ObservationList.Select(x => x.Pm10_atm).Average();

                    Sup.LogTraceInfoMessage($"Minutevalues data: {MinuteValues.Pm1_atm:F1}; {MinuteValues.Pm25_atm:F1}; {MinuteValues.Pm10_atm:F1};");
                }

                // Renew the observationlist
                ObservationList.Clear();
                // ObservationList = new List<PMSensordata>();  // The old list disappears through the garbage collector.
            }

            return;
        }
Ejemplo n.º 3
0
        public void SetMinuteValuesFromObservations()
        {
            if (Sensor.Valid)
            {
                Sup.LogTraceInfoMessage($"SetMinuteValuesFromObservations: Creating minutevalues as average of the 10 second observations... {SensorUsed}");

                if (Program.CUSensorsSwitch.TraceInfo)
                {
                    int i = 0;
                    foreach (I2cSensordata entry in ObservationList)
                    {
                        Sup.LogTraceInfoMessage($"Observationlist data {i++}: {entry.Humidity:F0}; {entry.TemperatureC:F1}; {entry.TemperatureF:F1}");
                    }
                }

                MinuteValues.Humidity     = ObservationList.Select(x => x.Humidity).Average();
                MinuteValues.TemperatureC = ObservationList.Select(x => x.TemperatureC).Average();
                MinuteValues.TemperatureF = ObservationList.Select(x => x.TemperatureF).Average();

                Sup.LogTraceInfoMessage($"Minutevalues data: {MinuteValues.Humidity:F0}; {MinuteValues.TemperatureC:F1}; {MinuteValues.TemperatureF:F1};");

                // Renew the observationlist
                ObservationList.Clear();
                //ObservationList = new List<I2cSensordata>();  // The old list disappears through the garbage collector.
            }

            return;
        }
Ejemplo n.º 4
0
        internal async Task Send(EmulateAirLink thisEmulator)
        {
            string HTDataToSend;
            string PMDataToSend;

            HTDataToSend = "{ " +
                           $"\"timestamp:\" : \"{DateTime.Now}\", " +
                           $"\"sensordatavalues\" : [" +
                           $"{{ \"value_type\":\"temperature\",\"value\":\"{thisEmulator.TemperatureC:F1}\" }}," +
                           $"{{ \"value_type\":\"humidity\",\"value\":\"{thisEmulator.Humidity:F1}\"}}" +
                           $"]" +
                           "}";

            PMDataToSend = "{ " +
                           $"\"timestamp:\" : \"{DateTime.Now}\", " +
                           $"\"sensordatavalues\" : [" +
                           $"{{ \"value_type\":\"P1\",\"value\":\"{thisEmulator.PM10_last:F2}\"}}," +
                           $"{{ \"value_type\":\"P2\",\"value\":\"{thisEmulator.PM25_last:F2}\"}}" +
                           $"]" +
                           "}";

            Sup.LogTraceInfoMessage($" PMDataToSend {PMDataToSend} ");
            Sup.LogTraceInfoMessage($" HTDateToSend {HTDataToSend} ");

            await PostToSensorCommunity(HTDataToSend, PMDataToSend);
        }
Ejemplo n.º 5
0
 public SHT31Device(Support s, string Name)
 {
     Sup        = s;
     SensorUsed = I2cSensorsSupported.SHT31;
     Valid      = true;
     Sup.LogTraceInfoMessage($"I2cSensorDevice SHT31 Constructor...{Name}, Valid = {Valid}");
     Sup.LogTraceInfoMessage($"Print AddressDetected for SensorUsed: {I2C.i2cAddressDetected[ (int) SensorUsed ]} for {SensorUsed}");
 }
Ejemplo n.º 6
0
        public override void DoWork(I2C thisSensor)
        {
            I2cSensordata thisReading = new I2cSensordata();

            Sup.LogTraceInfoMessage($"I2cSimulatorDevice {SensorUsed}: DoWork routine entry");
            // new DateTime(1970, 1, 1)
            thisReading.Humidity     = 70;
            thisReading.TemperatureF = 77.0;
            thisReading.TemperatureC = 25.0;

            thisSensor.ObservationList.Add(thisReading);
        }
Ejemplo n.º 7
0
        public PMS1003Device(Support s, string Name)
        {
            Sup = s;
            Sup.LogTraceInfoMessage($"DoPMS1003Device: Constructor...{Name}");

            try
            {
                SensorUsed = (SerialSensorsSupported)Enum.Parse(typeof(SerialSensorsSupported), Name, true);
                Port       = new DefinitionSerialPort(Sup, Name);
                Valid      = true;
            }
            catch (Exception e) when(e is ArgumentException || e is ArgumentNullException)
            {
                // We arrive here if the sensor does not exist in the Enum definition
                Sup.LogTraceErrorMessage($"Serial: Exception on Serial Port definitions in Inifile : {e.Message}");
                Sup.LogTraceErrorMessage("No use continuing when the particle sensor is not there - trying anyway");
                Valid = false;
            }
        }// PMS1003 Constructor
Ejemplo n.º 8
0
        public void DoAirLink()
        {
            // For Airquality (AirNow) and nowscast documentation: see Program.cs
            // We get here from the main loop once per minute

            Sup.LogTraceInfoMessage($"DoAirLink: Adding minutevalues to the averageslists...");

            TemperatureC = I2cDevice.MinuteValues.TemperatureC;
            TemperatureF = I2cDevice.MinuteValues.TemperatureF;
            Humidity     = I2cDevice.MinuteValues.Humidity;

            PM1_last = SerialDevice.MinuteValues.Pm1_atm;

            // 14.8 + (0.3834 * PM25) + (-0.1498 * rHum) + (-0.1905 * temperature)
            if (DoCalibrated)
            {
                PM25_last = 14.8 + 0.3834 * SerialDevice.MinuteValues.Pm25_atm + -0.1498 * Humidity + -0.1905 * TemperatureC;
            }
            else
            {
                PM25_last = SerialDevice.MinuteValues.Pm25_atm;
            }

            // 14.7 + (0.3151 * PM10) + (-0.0948 * rHum) + (0.2445 * temperature)
            if (DoCalibrated)
            {
                PM10_last = 14.7 + 0.3151 * SerialDevice.MinuteValues.Pm10_atm + -0.0948 * Humidity + 0.2445 * TemperatureC;
            }
            else
            {
                PM10_last = SerialDevice.MinuteValues.Pm10_atm;
            }

            if (PM25_last_1_hourList.Count == 60)
            {
                PM25_last_1_hourList.RemoveAt(0);
            }
            PM25_last_1_hourList.Add(PM25_last);
            Sup.LogTraceInfoMessage($"DoAirLink: PM25_last_1_hourList - count: {PM25_last_1_hourList.Count} / Average: {PM25_last_1_hourList.Average():F1}");

            if (PM25_last_3_hourList.Count == 3 * 60)
            {
                PM25_last_3_hourList.RemoveAt(0);
            }
            PM25_last_3_hourList.Add(PM25_last);
            Sup.LogTraceInfoMessage($"DoAirLink: PM25_last_3_hourList - count: {PM25_last_3_hourList.Count} / Average {PM25_last_3_hourList.Average():F1}");

            if (PM25_last_24_hourList.Count == 24 * 60)
            {
                PM25_last_24_hourList.RemoveAt(0);
            }
            PM25_last_24_hourList.Add(PM25_last);
            Sup.LogTraceInfoMessage($"DoAirLink: PM25_last_24_hourList - count: {PM25_last_24_hourList.Count} / Average {PM25_last_24_hourList.Average():F1}");

            if (PM10_last_1_hourList.Count == 60)
            {
                PM10_last_1_hourList.RemoveAt(0);
            }
            PM10_last_1_hourList.Add(PM10_last);
            Sup.LogTraceInfoMessage($"DoAirLink: PM10_last_1_hourList - count: {PM10_last_1_hourList.Count} / Average {PM10_last_1_hourList.Average():F1}");

            if (PM10_last_3_hourList.Count == 3 * 60)
            {
                PM10_last_3_hourList.RemoveAt(0);
            }
            PM10_last_3_hourList.Add(PM10_last);
            Sup.LogTraceInfoMessage($"DoAirLink: PM10_last_3_hourList - count: {PM10_last_3_hourList.Count} / Average {PM10_last_3_hourList.Average():F1}");

            if (PM10_last_24_hourList.Count == 24 * 60)
            {
                PM10_last_24_hourList.RemoveAt(0);
            }
            PM10_last_24_hourList.Add(PM10_last);
            Sup.LogTraceInfoMessage($"DoAirLink: PM10_last_24_hourList - count: {PM10_last_24_hourList.Count} / Average {PM10_last_24_hourList.Average():F1}");

#if PARANOIA
            // Do a paranoia check on the queue lengths: this should not be excuted in a release version
            // Print message to logfile if such thing occurs. Note that above the checks are on equal of the count value.
            // As soon as the value goes above, it is an uncorrectable issue.
            if (PM25_last_1_hourList.Count > 60)
            {
                Sup.LogTraceErrorMessage($"DoAirLink: PM25_last_1_hourList - count: {PM25_last_1_hourList.Count} / Average: {PM25_last_1_hourList.Average():F1}");
            }
            if (PM25_last_3_hourList.Count > 3 * 60)
            {
                Sup.LogTraceErrorMessage($"DoAirLink: PM25_last_3_hourList - count: {PM25_last_3_hourList.Count} / Average: {PM25_last_3_hourList.Average():F1}");
            }
            if (PM25_last_24_hourList.Count > 24 * 60)
            {
                Sup.LogTraceErrorMessage($"DoAirLink: PM25_last_24_hourList - count: {PM25_last_24_hourList.Count} / Average: {PM25_last_24_hourList.Average():F1}");
            }
            if (PM10_last_1_hourList.Count > 60)
            {
                Sup.LogTraceErrorMessage($"DoAirLink: PM10_last_1_hourList - count: {PM10_last_1_hourList.Count} / Average: {PM10_last_1_hourList.Average():F1}");
            }
            if (PM10_last_3_hourList.Count > 3 * 60)
            {
                Sup.LogTraceErrorMessage($"DoAirLink: PM10_last_3_hourList - count: {PM10_last_3_hourList.Count} / Average: {PM10_last_3_hourList.Average():F1}");
            }
            if (PM10_last_24_hourList.Count > 24 * 60)
            {
                Sup.LogTraceErrorMessage($"DoAirLink: PM10_last_24_hourList - count: {PM10_last_24_hourList.Count} / Average: {PM10_last_24_hourList.Average():F1}");
            }
#endif

            NowCast25 = CalculateNowCast(PM25_last_24_hourList);
            NowCast10 = CalculateNowCast(PM10_last_24_hourList);

            return;
        }
Ejemplo n.º 9
0
        void Init()
        {
            bool NoSerialDevice = false;
            bool NoI2cDevice    = false;

            // Setup logging and Ini
            Sup = new Support();

            Sup.LogDebugMessage(message: "Init() : Start");

            string AirLinkPMDevice = "";
            string AirLinkTHDevice = "";

            Console.CancelKeyPress += new ConsoleCancelEventHandler(CtrlCHandler);
            CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;

            // Setup tracing
            Trace.Listeners.Add(new TextWriterTraceListener($"log/{DateTime.Now.ToString( "yyMMddHHmm", CultureInfo.InvariantCulture )}sensors.log"));
            Trace.AutoFlush = true;
            CUSensorsSwitch = new TraceSwitch("CUSensorsSwitch", "Tracing switch for CUSensors")
            {
                Level = TraceLevel.Verbose
            };

            Sup.LogDebugMessage($"Initial {CUSensorsSwitch} => Error: {CUSensorsSwitch.TraceError}, Warning: {CUSensorsSwitch.TraceWarning}, Info: {CUSensorsSwitch.TraceInfo}, Verbose: {CUSensorsSwitch.TraceVerbose}, ");

            string thisTrace = Sup.GetSensorsIniValue("General", "TraceInfo", "Warning");     // Verbose, Information, Warning, Error, Off

            // Now set the Trace level to the wanted value
            switch (thisTrace.ToLower())
            {
            case "error": CUSensorsSwitch.Level = TraceLevel.Error; break;

            case "warning": CUSensorsSwitch.Level = TraceLevel.Warning; break;

            case "info": CUSensorsSwitch.Level = TraceLevel.Info; break;

            case "verbose": CUSensorsSwitch.Level = TraceLevel.Verbose; break;

            default: CUSensorsSwitch.Level = TraceLevel.Off; break;
            }

            Sup.LogDebugMessage($"According to Inifile {CUSensorsSwitch} => Error: {CUSensorsSwitch.TraceError}, Warning: {CUSensorsSwitch.TraceWarning}, Info: {CUSensorsSwitch.TraceInfo}, Verbose: {CUSensorsSwitch.TraceVerbose}, ");

            // Determine which sensor has to be for the AirLink:
            AirLinkEmulation = Sup.GetSensorsIniValue("General", "AirLinkEmulation", "false").Equals("true", StringComparison.OrdinalIgnoreCase);
            AirLinkPMDevice  = Sup.GetSensorsIniValue("AirLinkDevices", $"PMdevice", "");
            AirLinkTHDevice  = Sup.GetSensorsIniValue("AirLinkDevices", $"THdevice", "");

            // Check if we want AirLinkEmulation and do accordingly
            //
            if (AirLinkEmulation)
            {
                Sup.LogDebugMessage(message: "Init : Creating the AirLink Emulator and the Webserver");
                thisEmulator  = new EmulateAirLink(Sup);
                thisWebserver = new WebServer(Sup, thisEmulator);
            }

            // Do the Serial devices
            Sup.LogDebugMessage(message: "Init : Creating the Serial devices");
            for (int i = 0; i < MaxNrSerialSensors; i++)
            {
                string DeviceName = Sup.GetSensorsIniValue("SerialDevices", $"Serial{i}", "");
                thisSerial[i] = new Serial(Sup, DeviceName);
                if (AirLinkEmulation && $"Serial{i}" == AirLinkPMDevice)
                {
                    Sup.LogDebugMessage(message: $"Init : Serial{i} is AirLink device");
                    thisSerial[i].IsAirLinkSensor = true;
                    thisEmulator.SetSerialDevice(thisSerial[i]);
                }

                if (i == 0 && string.IsNullOrEmpty(DeviceName))
                {
                    NoSerialDevice = true;
                    break;
                }
            }// Serial devices

            // Do the i2c devices
            // Define the driver on this level so we only have one driver in the system on which we open all connections
            Sup.LogTraceInfoMessage(message: "Init : Creating the I2C driver");
            ThisDriver = new I2cDriver(ProcessorPin.Gpio02, ProcessorPin.Gpio03, false);
            Sup.LogTraceInfoMessage(message: $"Init : created the I2cDriver {ThisDriver}");
            I2C.DetectSensors(Sup);

            for (int i = 0; i < MaxNrI2cSensors; i++)
            {
                string DeviceName = Sup.GetSensorsIniValue("I2CDevices", $"I2C{i}", "");
                thisI2C[i] = new I2C(Sup, DeviceName);
                if (AirLinkEmulation && $"I2C{i}" == AirLinkTHDevice)
                {
                    Sup.LogDebugMessage(message: $"Init : I2C{i} is AirLink device");
                    thisI2C[i].IsAirLinkSensor = true;
                    thisEmulator.SetI2cDevice(thisI2C[i]);
                }

                if (i == 0 && string.IsNullOrEmpty(DeviceName))
                {
                    NoI2cDevice = true;
                    break;
                }
            }// i2c devices

            if (AirLinkEmulation && (NoI2cDevice || NoSerialDevice))
            {
                Sup.LogDebugMessage("Init: At leat one serial and one I2c device is required for PM and T/H in AirLink emulation");
                Environment.Exit(0);
            }

            if (AirLinkEmulation)
            {
                Sup.LogDebugMessage(message: $"Init : Starting the webserver");
                thisWebserver.Start();

                // Do the SensorCommunity Init
                DoSensorCommunity = Sup.GetSensorsIniValue("General", "SensorCommunity", "false").Equals("true", StringComparison.OrdinalIgnoreCase);
                Sup.LogDebugMessage(message: $"Init : Starting SensorCommunity: SensorCommunity is {DoSensorCommunity}");

                if (DoSensorCommunity)
                {
                    thisSensorCommunity = new SensorCommunity(Sup);
                }
            }
        } // Init
Ejemplo n.º 10
0
        async Task RealMain()
        {
            Init();

            Sup.LogDebugMessage(message: "ZeroWsensors : ----------------------------");
            Sup.LogDebugMessage(message: "ZeroWsensors : Entering Main");

            Console.WriteLine($"{Sup.Version()} {Sup.Copyright}");
            Sup.LogDebugMessage($"{Sup.Version()} {Sup.Copyright}");

            Console.WriteLine("This program comes with ABSOLUTELY NO WARRANTY;\n" +
                              "This is free software, and you are welcome to redistribute it under certain conditions.");
            Sup.LogDebugMessage("This program comes with ABSOLUTELY NO WARRANTY;\n" +
                                "This is free software, and you are welcome to redistribute it under certain conditions.");


            #region MainLoop

            // Start the loop
            using (StreamWriter of = new StreamWriter("CUSensorArray.txt", true))
            {
                int Clock = 0;

                do
                {
                    string thisLine = "";

                    // Do this condional because the ctrl-c interrupt can be given aanywhere.
                    Sup.LogTraceInfoMessage(message: "ZeroWsensors : Getting sensor values from the Main 10 second loop");

                    if (Continue)
                    {
                        Clock++;

                        for (int i = 0; i < MaxNrSerialSensors; i++)
                        {
                            thisSerial[i].DoWork();                                                 // Takes care of the reading of the serial devices
                        }
                        for (int i = 0; i < MaxNrI2cSensors; i++)
                        {
                            thisI2C[i].DoWork();                                                    // Takes care of the  reading of the I2C devices
                        }
                        // So we came here 6 times every 10 seconds. Create the minute values and remove the existing list, create a new one
                        // The average values are always real averages even if some fetches failed in which case the list is shorter
                        // This is the basic work of the sensor handler: fetch data and write to local logfile

                        if (Clock == 6)
                        {
                            Clock = 0;

                            for (int i = 0; i < MaxNrSerialSensors; i++)
                            {
                                thisSerial[i].SetMinuteValuesFromObservations();
                            }
                            for (int i = 0; i < MaxNrI2cSensors; i++)
                            {
                                thisI2C[i].SetMinuteValuesFromObservations();
                            }

                            // Now we do the AirLink handling which is assumed to be called once per minute with the observation list to create
                            // all other necessary lists and calculated values from there
                            if (AirLinkEmulation)
                            {
                                thisEmulator.DoAirLink();

                                // When all done Write out the values to SensorCommunity
                                if (DoSensorCommunity)
                                {
                                    await thisSensorCommunity.Send(thisEmulator);
                                }
                            }

                            // Write out to the logfile
                            for (int i = 0; i < MaxNrSerialSensors; i++)
                            {
                                thisLine += $";{thisSerial[ i ].MinuteValues.Pm1_atm:F1};{thisSerial[ i ].MinuteValues.Pm25_atm:F1};{thisSerial[ i ].MinuteValues.Pm10_atm:F1}";
                            }
                            for (int i = 0; i < MaxNrI2cSensors; i++)
                            {
                                thisLine += $";{thisI2C[ i ].MinuteValues.TemperatureC:F1};{thisI2C[ i ].MinuteValues.Humidity:F0}";
                            }

                            Sup.LogTraceInfoMessage(message: "ZeroWsensors : Writing out the data to the logfile");
                            Sup.LogTraceInfoMessage(message: $"{DateTime.Now:dd-MM-yyyy HH:mm}{thisLine}");
                            of.WriteLine($"{DateTime.Now:dd-MM-yyyy HH:mm}{thisLine}");
                            of.Flush();
                        }
                    }

                    // This is really hardcoded and should NOT change. The whole thing is based on 6 measurements per minute, so loop every 10 seconds
                    Thread.Sleep(10000);
                } while (Continue);   // Do-While
            } // Using the datafile

            #endregion

            Sup.LogDebugMessage("SensorArray Gracefull exit... End");

            Trace.Flush();
            Trace.Close();

            return;
        } // Real main()