Skip to main content

Stromverbrauch messen an einem Stromzähler mit S0 Schnittstelle

Nachdem vor einiger Zeit ein eigener Stromzähler für den Serverraum eingebaut wurde, der auch eine S0 Schnittstelle besitzt, entstand der Wunsch den Energieverbrauch auch in "Echtzeit" zu erfassen.

Zum Glück lag auch noch ein uralt Arduino herum. Ein bischen Herumsuchen im Netz (auf der arduino.cc Website gibts eine gute Dokumentation mit Beispielcode) führte schliesslich zu dieser Seite mit ein ausreichend Information für Elektronikdeppen wie mich.

Allerdings wollte ich den Stromverbrauch in unser munin Monitoringsystem einbinden. Aus diesem Grund verband ich den im Netz gefundenen Code mit dem "serial event" Beispielcode von der Arduino Website, sodass das Munin-Plugin alle 5 Minuten den momentanen Energieverbrauch abfragen kann.

Hier gibts noch den Code der auf dem Arduino läuft:

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete
const byte counterPin = 3;       // which pin is connected to the S0 interface
unsigned long millisBetween;
unsigned long lastMillis;
byte lastState;

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
  // initialize pin
  pinMode(counterPin, INPUT);
  digitalWrite(counterPin, LOW);
  // initialize time measure variables
  millisBetween = 0;
  lastMillis = 0;
  lastState = 0;
}

void loop() {
  unsigned long time = millis();
  byte val = digitalRead(counterPin);
 
  if (val == HIGH && lastState == LOW) {
    millisBetween = time-lastMillis;
    lastMillis = time;
  }
 
  lastState = val;
  unsigned long dataToWrite = millisBetween;
 
  if (stringComplete) {
    if (inputString.equals("GET\n")) {
      Serial.println(dataToWrite);
    }
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent occurs whenever a new data comes in the
hardware serial RX.  This routine is run between each
time loop() runs, so using delay inside loop can delay
response.  Multiple bytes of data may be available.
*/
void serialEvent() {
        int len = 0;
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
                if (len < 200) inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
                len++;
  }
}

Und dann noch den des Munin-Plugins:

#!/usr/bin/env python

import serial
import time
import sys
import os
from serial import SerialException, SerialTimeoutException


TERMINAL = os.getenv('serial_terminal', '/dev/ttyUSB0')
BAUDRATE = os.getenv('serial_baudrate', '9600')
TIMEOUT = os.getenv('serial_timeout', 2)
PULSE_RATE = os.getenv('s0_pulse_rate', 800)

def ser_init():
        ser = serial.Serial(TERMINAL, BAUDRATE, timeout=TIMEOUT)
        return ser

def conf():
        print "graph_title power consumption"
        print "graph_args --base 1000 -l 0"
        print "graph_vlabel Powerconsumtion Watts"
        print "graph_category system"
        print "graph_info Displays the powerconsumption of the whole server room including aircondition"
        print "power.label power"

def autoconf():
        try:
                ser_init()
                print "Yes"
        except ValueError:
                print "No (Baudrate or other values out of range)"
        except SerialException:
                print "No (Device " + TERMINAL + " not found or could not be configured)"

def report():
        value = ""
        try:
                ser = ser_init()
                ser.write("GET\n")
                value = int(ser.readline())
                ser.close()
                value = 3600000000/(value * PULSE_RATE)
        except:
                value = "U"
        print "power.value", value

def debug():
        print "Terminal " + TERMINAL
        print "Baudrate " + BAUDRATE
        print "Timeout " + str(TIMEOUT)

def main():
        if len(sys.argv)>1:
                command = sys.argv[1]
        else:
                command = ""

        if command == "autoconf":
                autoconf()
        elif command == "config":
                conf()
        elif command == "debug":
                debug()
        else:
                report()

if __name__ == "__main__":
        main()