MQTT, Arduino, Old Ammeters and Bandwidth Monitoring

Thanks to some help from @knolleary the arduino pubsub library now works with mosquitto. I have now completed my bandwidth monitor project which I want to document in this post.

I have mentioned in previous posts that I use various scripts and sensors to feed data into the open source MQTT broker mosquitto. Currently all data is posted to pachube, rather than everything being online I decided I wanted some physical feedback. Having made an impulse buy of two vintage Ferranti ammeters using these to display some of my data seemed like obvious answer! The code on the arduino basically just displays a number passed by MQTT on the meter and therefore could be applied to any measurement one cared to choose.

The basic idea of this system is to monitor the current internet speed usage and display it on the ammeter. The system is based around an arduino with ethernet shield which acts as an MQTT client, this subscribes to the downstream bandwidth topic on my MQTT broker, receives the messages and changes the level of a PWM output pin on the arduino which causes the meter to show the appropriate level. The meter displays the current through a resistor which is varied by the PWM signal from the arduino. The reading on the meter corresponds to the current internet speed usage as a percentage of the overall theoretical available bandwidth.

The Arduino Code

As this is quite well commented I won't go through it, but it serves as a good example of how to receive MQTT messages using an arduino:

#include <Ethernet.h>
#include <PubSubClient.h>

//Setup network connection
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { <arduino ip> };
byte subnet[] = {<subnet>};
byte gateway[] = {<router ip>};

//MQTT Broker
byte server[] = {<mqtt broker (mosquitto/RSMB)>};
int port = 1883;
//Meter output spin
int meterPin = 9;

//Set initial bandwidth
float out = 0;

//MQTT client setup
PubSubClient client(server, port, callback);

//Add callback for when a message is recieved
//
// Takes bandwidth as 4 digit number e.g 44 = 0044
void callback(char* topic, byte* payload,int length) {
  //reset value
  out=0;

  //convert receieved byte array into number
  for(int i=0;i<4;i++)
  {
    //get the byte
    byte ardValue = payload[i];
    //multiply it by 1/10/100 or 1000
    double tens = pow(10,(3-i));
    //convert the byte to either 1/10/100/1000
    float ardOut = tens * (ardValue-48);
    //add to total output
    out +=ardOut;
  }

  //scale number between 0-4000 to 0-255 for output
  out = map(out, 0, 4000, 0, 255);

  //print result to serial port for debugging
  Serial.println(out);

  //write output to meter
  analogWrite(meterPin, out);
}

//setup method
void setup()
{
  //start ethernet connection
  Ethernet.begin(mac, ip, gateway, subnet);

  //start serial connection for debugging
  Serial.begin(9600);

  //connect to MQTT Broker
  client.connect(&quot;arduino&quot;);

  //Subscribe to topic bandDown
  client.subscribe(&quot;bandDown&quot;);
}

//main loop
void loop()
{
  //Tell the MQTT broker we're still here
  client.loop();
}

The PHP script that provides the bandwidth data resides on my sheevaplug and queries my router for an XML file with the appropriate details, I talked about this in a previous post.