General

Arduino Mod for Open Hardware Monitor ( to control a System Fan)

userHead LNC-SPN 2017-11-02 20:40:16 36071 Views15 Replies

Hi LattePanders!, if you have installed a system fan for your LattePanda (like me) this mod for Open Hardware Monitor its useful to control the fan (Power On when system start - Power Off when system shutdown - Activate by CPU temp)

You can use a Relay or a NPN Transistor (PWM not implemented yet).

Installation
Download the RAR OpenHardwareMonitor(Arduino Mod).rar 

Image

Arduino Setup
Options - Arduino - COM Port (Select your Arduino COM, AUTO by default)
Options - Arduino - Fan Controller - GPIO Pin (Select the Relay or Transistor Pin)
Options - Arduino - Fan Controller - Enable (You can also select "Activate by CPU temp")
(To change the Pin you need to Disable first)

Important= Options - Run On Windows Startup
Optional = Options - Start Minimized
Recomended= View - Show Gadget (select the items from the list (Right click-Show in Gadget) 

Image

How it works?
Using the Standard Firmata library from the Arduino Leonardo side and a custom LattePanda Firmata library (only digitalWrite, low CPU usage)

ArduinoCustomFirmata.cs

using System;
using System.IO.Ports;
using System.Threading;
using System.Linq;

namespace LattePanda.CustomFirmata
{
    class Arduino
    {
        public const byte LOW = 0;
        public const byte HIGH = 1;
        public const byte OUTPUT = 1;

        public Arduino(string serialPortName)
        {
            _arduinoSerialPort = new SerialPort();

            if (serialPortName == String.Empty)
            {
                _arduinoSerialPort.PortName = List().ElementAt(List().Length - 1);
            }
            else { _arduinoSerialPort.PortName = serialPortName; }
            _arduinoSerialPort.BaudRate = 57600;
            _arduinoSerialPort.DataBits = 8;
            _arduinoSerialPort.Parity = Parity.None;
            _arduinoSerialPort.StopBits = StopBits.One;

            Open();
        }
        public static string[] List()
        {
            return SerialPort.GetPortNames();
        }

        public void Open()
        {
            _arduinoSerialPort.DtrEnable = true;
            _arduinoSerialPort.Open();
            Thread.Sleep(1000);
        }
        public void Close()
        {
            if (_arduinoSerialPort.IsOpen == true)
            {
              _arduinoSerialPort.Close();
            }
           
        }
        public void pinMode(int pin, byte mode)
        {
            byte[] message = new byte[3];
            message[0] = (byte)(SET_PIN_MODE);
            message[1] = (byte)(pin);
            message[2] = (byte)(mode);
            _arduinoSerialPort.Write(message, 0, 3);
            message = null;
        }
        public void digitalWrite(int pin, byte value)
        {
            int portNumber = (pin >> 3) & 0x0F;
            byte[] message = new byte[3];

            if ((int)value == 0)
                _digitalOutputData[portNumber] &= ~(1 << (pin & 0x07));
            else
                _digitalOutputData[portNumber] |= (1 << (pin & 0x07));

            message[0] = (byte)(DIGITAL_MESSAGE | portNumber);
            message[1] = (byte)(_digitalOutputData[portNumber] & 0x7F);
            message[2] = (byte)(_digitalOutputData[portNumber] >> 7);
            _arduinoSerialPort.Write(message, 0, 3);
        }

        private const int MAX_DATA_BYTES = 64;
        private const int TOTAL_PORTS = 2;
        private const int DIGITAL_MESSAGE = 0x90; // send data for a digital port
        private const int SET_PIN_MODE = 0xF4; // set a pin to INPUT/OUTPUT/PWM/etc
        private volatile int[] _digitalOutputData = new int[MAX_DATA_BYTES];
        private SerialPort _arduinoSerialPort;
    }
}

 

Using ArduinoUtilities class that have a loop to know every second the CPU temp, compare to the max temp setted by user and power on or power off the fan.

using System;
using System.Threading;
using OpenHardwareMonitor.Hardware;
using LattePanda.CustomFirmata;

namespace OpenHardwareMonitor.Utilities
{
    public class ArduinoUtilities
    {
        private Arduino arduino;
        private PersistentSettings settings;
        public string ArduinoPortName = String.Empty;
        public int RelayFanPin;
        public int RelayFanByTemp;
        private bool ArduinoIsOpen;
        public bool RelayFanIsEnabled;
        public bool RelayFanByTempIsEnabled;
        private bool RelayFanIsOn;

        private Thread readCPUtemp = null;
        private volatile bool keepGetCPUtempRunning = true;

        public ArduinoUtilities(PersistentSettings settings)
        {
            this.settings = settings;
            ArduinoPortName = settings.GetValue("ArduinoPortName", (ArduinoPortName));
            RelayFanIsEnabled = settings.GetValue("RelayFanIsEnabled", (RelayFanIsEnabled));
            RelayFanPin = settings.GetValue("RelayFanPin", (RelayFanPin));
            RelayFanByTempIsEnabled = settings.GetValue("RelayFanByTempIsEnabled", (RelayFanByTempIsEnabled));
            RelayFanByTemp = settings.GetValue("RelayFanByTemp", (RelayFanByTemp));

            if (RelayFanIsEnabled == true && RelayFanByTempIsEnabled == true)
            {
                ActivateRelayFanByTemp();
            }
            else
            {
                if (RelayFanIsEnabled == true)
                {
                    RelayFanON();
                }
            }
        }

        private void OpenArduino()
        {
            arduino = new Arduino(ArduinoPortName);
            ArduinoIsOpen = true;
        }
        public void CloseArduino()
        {
            arduino.Close();
            ArduinoIsOpen = false;
        }

        private void GetCPUTemp()
        {
            while (keepGetCPUtempRunning)
            {
                int CPUtemp;
                var myComputer = new Computer { CPUEnabled = true };
                myComputer.Open();

                foreach (var hardwareItem in myComputer.Hardware)
                {
                    hardwareItem.Update();
                    hardwareItem.GetReport();

                    foreach (var sensor in hardwareItem.Sensors)
                    {
                        if (sensor.SensorType == SensorType.Temperature)
                        {
                            CPUtemp = (int)sensor.Value;
                            if (CPUtemp >= RelayFanByTemp)
                            {
                                RelayFanON();
                            }
                            else
                            {
                                RelayFanOFF();
                            }
                        }
                    }
                }

                Thread.Sleep(1000);
            }
        }
        public void ActivateRelayFanByTemp()
        {
            keepGetCPUtempRunning = true;
            if (readCPUtemp == null)
            {
                readCPUtemp = new Thread(GetCPUTemp);
                readCPUtemp.IsBackground = true;
                readCPUtemp.Start();
            }
        }
        public void DeactivateRelayFanByTemp()
        {
            keepGetCPUtempRunning = false;
            readCPUtemp = null;
        }

        public void RelayFanON()
        {
            if (ArduinoIsOpen == false)
            { OpenArduino(); }

            if (RelayFanIsOn == false)
            {
                arduino.pinMode(RelayFanPin, Arduino.OUTPUT);
                arduino.digitalWrite(RelayFanPin, Arduino.HIGH);
                RelayFanIsOn = true;
            }
        }
        public void RelayFanOFF()
        {
            if (ArduinoIsOpen == false)
            { OpenArduino(); }

            if (RelayFanIsOn == true)
            {
                arduino.pinMode(RelayFanPin, Arduino.OUTPUT);
                arduino.digitalWrite(RelayFanPin, Arduino.LOW);
                RelayFanIsOn = false;
            }
        }
        public void Close()
        {
            if (RelayFanByTempIsEnabled == true)
            {
                RelayFanOFF();
                keepGetCPUtempRunning = false;
                readCPUtemp = null;
            }
            if (RelayFanIsEnabled == true)
            {
                RelayFanOFF();
                CloseArduino();
            }
        }
    }
}

 

Testing

Stable on LattePanda 4GB/64GB Z8300 CPU - Windows 10 64 bits Creators Update

Not tested on LattePanda 2GB/32GB Z8300 CPU - Windows 10 32 bits

Not tested on LattePanda 4GB/64GB Z8350 CPU 

 

Feedback is much appreciated.

 

Credits/Copyright 

Michael Möller (http://openhardwaremonitor.org/)

Kevlin Sun (LattePanda.Firmata)

 

 

OpenHardwareMonitor_gadget.jpgOpenHardwareMonitor-Arduino.png