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()