using System; using System.Device.Gpio; using System.IO.Ports; using System.Threading; using Microsoft.Extensions.Logging; using PMS5003.Exceptions; namespace PMS5003 { /// /// PMS5003 digital universal particle concentration sensor. /// Datasheet: https://www.aqmd.gov/docs/default-source/aq-spec/resources-page/plantower-pms5003-manual_v2-3.pdf /// public class Pms5003 { public static Logger Logger; private readonly GpioController _gpioController; private readonly SerialPort _serialPort; private readonly short _pinSet; private readonly short _pinReset; private bool _isSleeping; /// /// Initializes the . /// /// The name of the serial port. /// The number of the SET pin. /// The number if the RESET pin. public Pms5003(string portSerialName, short pinSet, short pinReset) { _serialPort = new SerialPort(portSerialName, Pms5003Constants.DefaultBaudRate); _pinReset = pinReset; _pinSet = pinSet; _serialPort.Open(); if (Environment.OSVersion.Platform == PlatformID.Unix) { _gpioController = new GpioController(); if (pinSet >= 0) { _gpioController.OpenPin(_pinSet, PinMode.Output); _gpioController.Write(_pinSet, PinValue.High); } if (pinReset >= 0) { _gpioController.OpenPin(_pinReset, PinMode.Output); _gpioController.Write(_pinReset, PinValue.High); } } else { Logger?.LogWarning("Not running under Unix platform, skipping GPIO configuration."); } } /// /// Initializes the using /dev/ttyAMA0 serial port name. /// /// /// public Pms5003(short pinSet, short pinReset) : this("/dev/ttyAMA0", pinSet, pinReset) { } /// /// Initializes the using /dev/ttyAMA0 serial port name /// and no GPIO pins for SET and RESET. /// public Pms5003() : this("/dev/ttyAMA0", -1, -1) { } /// /// Reads the data from the sensor. /// /// The data. /// Thrown when the read fails. public Pms5003Data ReadData() { var currentTry = 0; const int maxRetries = 50; var buffer = new byte[32]; while (currentTry < maxRetries) { try { // Try to find start frame _serialPort.Read(buffer, 0, 1); if (buffer[0] != Pms5003Constants.StartByte1) { continue; } _serialPort.Read(buffer, 1, 1); if (buffer[1] != Pms5003Constants.StartByte2) { continue; } // Read rest of data _serialPort.Read(buffer, 2, 30); return Pms5003Data.FromBytes(buffer); } catch (Exception e) { Logger?.LogWarning(e.ToString()); Thread.Sleep(1000); } finally { currentTry += 1; } } throw new ReadFailedException(); } /// /// Resets the PMS5003 Sensor. /// public void Reset() { if (_gpioController == null || _pinReset < 0) return; _gpioController.Write(_pinReset, PinValue.Low); Thread.Sleep(200); _gpioController.Write(_pinReset, PinValue.High); } /// /// Enables Sleep Mode for the PMS5003 Sensor. /// public void Sleep() { if (_gpioController == null || _pinSet < 0) return; _isSleeping = true; _gpioController.Write(_pinSet, PinValue.Low); } /// /// Disables Sleep Mode for the PMS5003 Sensor. /// public void WakeUp() { if (_gpioController == null || _pinSet < 0) return; _isSleeping = false; _gpioController.Write(_pinSet, PinValue.High); } /// /// Checks if Sleep Mode is enabled. /// /// True if sensor is in Sleep Mode, false otherwise. public bool IsSleeping() { return _isSleeping; } ~Pms5003() { _serialPort.Close(); _gpioController?.Dispose(); } } }