I was looking for a simple telemetry sistem for my MMDVM repeater, wich is not in my house, so for me is very useful to check it remotely.

I fixed some requisites before starting the research of this system:

  • It should be compatible with the raspberry Pi;
  • It should read repeater voltage, current, temperatures, and it should check the presence of 220V, in order to detect a power blackout and prevent the UPS discharge;
  • Easy to embed the readings in the MMDVM Dashboard, possibly using gauges or similar nice graphic indicators.

After some research on the internet, I found something almost ready, but it was quite expensive and was not easy to customize.
So I started to think to a “DIY” solution. I searched for ready-to-use ADC boards, and I found a lot of sulutions on amazon or ebay, but most of them provides only 4inputs and 4 outputs, but I’m not interested at outputs channels, and 4 inputs were not enough for my purposes.
At the end of my researches, I bought the IC MCP3008, by Microchip, that is a 8 inputs, 10 bit Analog to digital converter equipped with and an SPI output interface ( http://ww1.microchip.com/downloads/en/DeviceDoc/21295C.pdf ). The IC could be powered directly from the 3,3V or 5V of the raspberry, and a python library is also available for this ADC ( https://github.com/adafruit/Adafruit_Python_MCP3008 ).
The ADC inputs can directly read temperature sensors and repeater main voltage (the maximum input is Vcc, so the voltage must be divided through a pair of resistors, obviously).
For the curren telemetry, I found a very simple and cheap hall effect sensor IC, the ACS712 series, by Alegro (see_datasheet).
The chip is available in SOIC8 SMD package, but the complete PCB with screw terminals are available on the ebay.
I bought a pair of ACS712-05 (5Ampere full scale) and a pair of ACS712-20 (20 Ampere full scale) form a Chinese supplier, and finally I got it after a 3 weeks.

I built a simple prototype board with L-C filters on the input and a voltage dividers on ch0, which is dedicated to the 12V acquisition.

Here below the very simple schematic diagram:


Here below prototype picture:



Note: in the picture some 3-way screw terminal are present, despite of 2-way terminal of schematic diagram. I simply brought the 5V on the third terminal, if a powered sensor is used (e.g. the current sensor board must be externally powered with a 5V).

The connection between the prototype board and the raspberry are done by female square pin wires, following the pinout of raspberry pi. The pinout is reported hereafter:

mcp3008pinoutThere are two possibilities to connect the IC to the raspy: the Software SPI or the hardware SPI. I choose the second one, so the connections are:

  • MCP3008 VDD to Raspberry Pi 3.3V
  • MCP3008 VREF to Raspberry Pi 3.3V
  • MCP3008 AGND to Raspberry Pi GND
  • MCP3008 DGND to Raspberry Pi GND
  • MCP3008 CLK to Raspberry Pi SCLK
  • MCP3008 DOUT to Raspberry Pi MISO
  • MCP3008 DIN to Raspberry Pi MOSI
  • MCP3008 CS/SHDN to Raspberry Pi CE0

The Raspberry Pi3 pinout is reported here below:

raspy pinout

For the first check of the interface, I put a 5V on one of the cannels, then I installed the adafruit python library and examples, following this procedure (see references for the complete guide):

sudo apt-get install build-essential python-dev python-smbus git
cd ~ (or directory where you want to install the package)
git clone https://github.com/adafruit/Adafruit_Python_MCP3008.git
cd Adafruit_Python_MCP3008
sudo python setup.py install

Then, if the installation is successful, we can go into the Adafruit directory and edit the file simplest.py. In order to use the Hardware SPI, the first part must be commented and the second part must be uncommented. The code will look like this:

# Software SPI configuration:
#CLK = 18
#MISO = 23
#MOSI = 24
#CS = 25
#mcp = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI)
# Hardware SPI configuration:
mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE))

I saved the simpletest.py, then I connected a pair of power supply at a random voltage between 0 and 5V on ch0 and ch1 of my prototype board, just for test. I launched the test file (sudo python simpletest.py) and I got the correct channel acquisition:


I tested all the channels providing a 5V to each input, and I verified the decimal value was near 1024, which is the full-scale range for a 10bit ADC.
Ok, it was the easier part of the work, but now…I want to show data on the MMDVM dashboard, which is written in PHP by DG9VH.
I tried some library available on the internet, but I had no time and knowledge to study and customize them.
In particular, the Calcinai PHPi library is very interesting, but it’s not ready for use. The user should create a ‘worker’ which runs in the background and is connected to via websockets (or similar).  It may not even need to be that complex if you’ve already got a database layer to cache the readings. If someone wants to work on it, please have a look at https://github.com/calcinai/phpi-websocket).

So I decided to try the quickest solution, although it’s very dirty and most of SW developers will dislike it.
I decided to run a python script through the “exec” command in php code, which execute shell commands. Once the python script has been executed, the 8 ADC readings are stored in a vector, then any conversion fron decimal to voltage/current/temperature is possible in php.

Once the date is acquired, it should be shown in a pleasant way on the dashboard. I searched for some beautiful and simple gauge and I found “coffeegauge”: http://bernii.github.io/gauge.js/

For the implementation of the acquisition routine and the gauge parameters, I followed the following steps:

1) Start from “example.py”, under the examples directory, and modify it in order to read the inputs only once (I deleted the cycle inside). Save it as “read_adc.py” in var/www/html/ directory.


import time
import Adafruit_GPIO.SPI as SPI
import Adafruit_MCP3008
# Hardware SPI configuration:
mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE))
#read and print all ADC channels
for i in range(8):

2) Give execution permission on the script:

chmod +x read_adc.py

3) Check the correct execution of the script:

python read_adc.py

see the output values on the screen and check they report the correct decimal value if compared to the input voltages present at the channels.

4) Download the script file gauge.min.js from http://bernii.github.io/gauge.js/ and copy it in the /var/www/html directory (or the root file declared in your html server config file)

5) Insert the following code inside var/www/html/custom.php file, which is executed and shown in the dashboard , under the section “custom info” (remember to enable int in the dashboard config file). Only ADC ch1 is reported, but you can copy-paste for every channel:

#Execute the python script and store channels readings into a vector
exec("sudo python ./read_adc.py", $adc);
#calculate the power supply voltage (4.35 is the resistive divider factor)
#create the canvas gauge_V and show ch1 value
<canvas width="200" height="150" id="gauge_V"></canvas>
#recall the script .js file
<script type="text/javascript">
#set gauge options
var opts_V = {
  angle: -0.2, // The span of the gauge arc
  lineWidth: 0.1, // The line thickness
  radiusScale: 0.8, // Relative radius
  pointer: {
    length: 0.6, // // Relative to gauge radius
    strokeWidth: 0.033, // The thickness
    color: '#000000' // Fill color
  limitMax: false,     // If false, max value increases automatically if value > maxValue
  limitMin: false,     // If true, the min value of the gauge will be fixed
  highDpiSupport: true,     // High resolution support
  staticZones: [
   {strokeStyle: "#30B32D", min: 0, max: 12}, // Green
   {strokeStyle: "#FFDD00", min: 12, max: 14}, // Yellow
   {strokeStyle: "#F03E3E", min: 14, max: 24}  // Red
staticLabels: {
  font: "10px sans-serif",  // Specifies font
  labels: [0,12,24],  // Print labels at these values
  color: "#000000",  // Optional: Label text color
  fractionDigits: 1  // Optional: Numerical precision. 0=round off.
var target = document.getElementById('gauge_V'); // your canvas element
var gauge = new Gauge(target).setOptions(opts_V); // create sexy gauge!
gauge.maxValue = 24; // set max gauge value
gauge.setMinValue(0);  // Prefer setter over gauge.minValue = 0
gauge.animationSpeed = 32; // set animation speed (32 is default value)
gauge.set(); // set actual value

Note: The “floor” function is used to decrease the decimal digit to 2.

6) Try the final effect loading custom.php in the browser or the complete index.php page.

If everything is ok, you should see the gauge 😉

The user can customize almost everything of the gauge (colors, aspect, dimensions, speed, angles, ecc..). For more details you can go to http://bernii.github.io/gauge.js/

The final effect is reported in the following screenshot:


The real dashboard can be reached at this address: http://iz7boj.ampr.org

Note1: the python script is executed only when the dashboard is loaded on the browser, so the current value is sampled in the moment of script execution and mantained until the browser is refreshed!
If the radio is transmitting, you’ll see something about 3,8Ampere, otherwise you’ll see abut 150mA, which is the consumption in receive mode.

Note2: that the 220V presence is not exactly the voltage at the plug. I simply connected a 5V power supply to one of the inputs.
Then, I inserted the following “if” case in custom.php:

if ($ch5>4){$RETE=220;} else {$RETE=0;}

In other words, if the 5V is present (V>4V), then I’ll show 220V in the indicator.
In my “to do list”, I’ll build an voltage divider that will ready the 220V..

The source code that I pasted for ch1 could be obviously repeated for every channel, and any math formulas can be implemented for other type of signals.

I hope someone can found some interesting trick to built is own telemetry interface!
It’s a “quick&dirty solution”, but I’m an HW man and have a basic php knowledge. Every software developer can do something better than me for sure 🙂

Best 73’s
Alfredo IZ7BOJ





import time
import Adafruit_GPIO.SPI as SPI
import Adafruit_MCP3008
# Hardware SPI configuration:
mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE))
#read and print all ADC channels
for i in range(8):