Monero (XMR) rig monitoring and auto-restart with Arduino – tutorial

Those who are running crypto currencies mining operation know about importance of good automation. There are plenty of software around that can help you achieve as much automation as possible for different crypto currencies. But sometimes soft reboot of mining software is not an option. Especially in highly beta ecosystem such as AMD RX Vega rigs with blockchain driver and Windows 10. Even after tweaking voltage and frequency for graphic cards, blockchain driver is unstable and many times leads to Windows bluescreen or freeze that requires manual restart of the rig.

Fortunately it’s quite easy and cheap to deploy good old Arduino with some additional pieces of hardware and make nice little hardware monitor which can check miner status and restart rig if there is no response. This time we will do it for Monero (XMR) mining with xmr-stak miner, which has it’s own stats server usually on port 420. For this hardware restart project we won’t actually care about hashrate but will only check if stats server is responsive or not. Moreover our hardware monitor won’t restart rig immediately when it detects that miner stats server doesn’t work but will give 5 minutes to software monitor to fix the issue (usually by restarting graphic card drivers and miner). It’s highly recommended to use software monitoring as well because usually it will be enough to get rig up and running. Hardware reset should be last resort in that everything else fails.

Total cost of this solution is under $15 for two rigs. Scaling for more rigs is even cheaper and only cost an additional relay which is below $2. It is possible to but modules with 4 – 16 relays which is even cheaper per relay.

For this particular implementation you will need:

  • Arduino Uno board
  • Arduino Uno ethernet shield
  • 2 x relay modules
  • 1 LED
  • 1 resistor (1k Ohm)
  • wires

First, we are going to connect Arduino Uno board and ethernet shield which is straight forward common sense. Ethernet shield will use pinsĀ 10, 11, 12, 13 so keep in mind not to use these for other purposes.

Relays should be connected to +5v pin, GND pin and control pin. Since there’s only one +5v pin you will need to share it somehow between these two relays. For two relays this can be done with some standard wire connectors without soldering. Relays will be controlled through digital pins 8 and 9. More relays could require a bit of soldering and making your own connectors.

There’s also red LED which is going to indicate that one or both rigs are not responding, since we won’t restart rigs immediately but only after set number of probes. LED and resistor will be connected between digital pin 2 and GND.

You can get Arduino sketch for this solution on GitHub. It’s quite easy to customize sketch. Just read comments in code. Keep in mind that in some cases DHCP won’t work with ethernet shield so you need to find unused IP address and assign it in the sketch. Also change IP addresses of your rigs. Default interval between response checks is around 60 seconds (60000 ms) but rig(node) will be restarted after 5 unsuccessful probes in a row. This can be changed as well thought configuration inside sketch.

/*
  Watchdog ethernet

 This sketch connects to a XMR-STAK-AMD nodes
 using an Arduino Wiznet Ethernet shield.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13

 created 8 Jan 2018
 by Zox - https://github.com/zoxxx
 */

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// Set the static IP address to use if the DHCP fails to assign
// Be sure to use IP address which is not already assigned to some other device in your network
IPAddress ip(192, 168, 0, 177);

// define led inication; some node isn't responding
#define LED_ALERT 2

// set this to number of mining nodes you're monitoring
#define NUMBER_OF_NODES 2
// and add nodes' ips in following fashion
IPAddress nodeIPs[NUMBER_OF_NODES] = { IPAddress(192,168,0,105), IPAddress(192,168,0,106) };
int nodeTimeouts[NUMBER_OF_NODES] = { 0, 0 };
// define pinouts for relays
int controlPins[NUMBER_OF_NODES] = { 8, 9 };

#define TIMEOUTS_BEFORE_RESTART 5 // number of timeouts before restart; we're giving internal monitor time to restart miner before we restart machine
#define REQ_INTERVAL 60000  // delay between requests, in milliseconds

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

void setup() {
  pinMode(LED_ALERT, OUTPUT);
  for (int i = 0; i < NUMBER_OF_NODES; i++) {
    pinMode(controlPins[i], OUTPUT);          // sets the digital pins as output
  }
  
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  /*
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  */
  Serial.println("Setup begining..");
  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
}

void loop() {
  checkNodes();
  ledAlert();
  delay(REQ_INTERVAL);
}

void checkNodes() {
  Serial.println("Checking nodes ..");
  for (int i = 0; i < NUMBER_OF_NODES; i++) {
    // if you get a connection, report back via serial:
    if (client.connect(nodeIPs[i], 420)) {
      client.stop();
      // reset timeouts if we got response
      nodeTimeouts[i] = 0;
      Serial.println("Node " + String(i) + " alive. Disconnecting.");
    } else {
      // if you didn't get a connection to the server:
      Serial.println("Connection to node " + String(i) + " failed.");
      restartNode(i);
    }
    delay(1000);
  }
  Serial.println();
}

void restartNode(int node) {
  nodeTimeouts[node]++;
  if (nodeTimeouts[node] >= TIMEOUTS_BEFORE_RESTART) {
    nodeTimeouts[node] = 0;
    digitalWrite(controlPins[node], HIGH);
    delay(1500);
    digitalWrite(controlPins[node], LOW); 
    Serial.println("Node " + String(node) + " restarted.");
  }
}

void ledAlert() {
  bool turnLEDon = false;
  for (int i = 0; i < NUMBER_OF_NODES; i++) {
    if (nodeTimeouts[i] != 0) {
      turnLEDon = true;
    }
  }
  if (turnLEDon) {
    digitalWrite(LED_ALERT, HIGH);          // show led alert
  } else {
    digitalWrite(LED_ALERT, LOW);
  }
}

 

For debugging purposes there’s some serial communication in form of console log messages so if you plan to use pins 0 and 1 you need to comment those out.

Finally, relays needs to be connected to restart pins on motherboard of your rig. On relay side use NO and COM pins because that means normally open circuit like your restart button. On motherboard part pins does not matter as long as they are used for restart button.

If you found this useful and would like to support further development into full fledged multiple rig monitoring and statistics tool you can send your XMR donations. Thanks!!!

48g1Tpd49YhK3Nx6d2ViuhCWszGfNV2KHcxEFMfPjFMsREbdsjsWWJJaEqHikeYfd4c66AoMG5z2McZ2eqP7ebgRMNXBjUM

Leave a Reply

Your email address will not be published. Required fields are marked *