Cleanup
[ampy.git] / run.py
diff --git a/run.py b/run.py
index c4bbf79ad5f81f17394b7bdac0373cdd98edcf36..3a599fc2f7d6931069d7462e79abe25e1bff5c8b 100755 (executable)
--- a/run.py
+++ b/run.py
@@ -5,49 +5,113 @@ file.
 """
 
 import os
-import pyaudio
-import wave
-import sys
 import struct
+import time
+
+import pyaudio
 
-DEVICE = 3  # which alsa decive to read
-CHUNK = 1024  # how many bytes at a time?
-FORMAT = pyaudio.paInt16  # Format
+FORMAT = pyaudio.paInt32  # Format
+STRUCTFORMAT = 'i'  # Format for python struct module
+DEVICE = 5  # which alsa decive to read
 RATE = 44100
 RECORD_SECONDS = 0.5
 
-VOLUME_CONSTANT = 11.975454545454545
-
-p = pyaudio.PyAudio()
-
-stream = p.open(format=FORMAT,
-                channels=1,  # Our ampmeter always returns 0 on the second channel
-                rate=RATE,
-                input=True,
-                input_device_index=DEVICE,
-                frames_per_buffer=CHUNK)
-
-while(True):
-    total = 0
-    for i in range(0, int(RATE * RECORD_SECONDS / CHUNK)):
-        data = stream.read(CHUNK, exception_on_overflow=False)
-        values = struct.unpack('h'*CHUNK, data)
-        #print(values)
-        chunk_total = 0
-        for value in values:
-            if value > 0:
-                chunk_total += value
-            else:
-                chunk_total -= value
-        chunk_total /= len(values)
-        #print(chunk_total)
-        total += chunk_total
-    avg = total / int(RATE * RECORD_SECONDS / CHUNK)
-    watts = avg / VOLUME_CONSTANT
-    print("average {:.0f}W".format(watts))
-    os.system("rrdtool update power.rrd N:{:.0f}".format(watts))
-
-stream.stop_stream()
-stream.close()
-p.terminate()
+VOLUME_CONSTANT = 132360.98315789475
+
+# https://www.actutem.com/valeur-crete-moyenne-et-efficace-dune-tension-ac/
+# math.pi/math.sqrt(2)/2 = 1.1107207345395915
+
+# Pour 30 A à 230V ( 6900 W )
+# abs(Sndmax) = 2147483520
+# Sndavg = 2147483520/math.pi = 683565234.8327662
+# Sndeff = 683565234.8327662 * 1.1107207345395915 = 759250079.7391784
+
+# https://fr.wikipedia.org/wiki/Compteur_%C3%A9lectrique
+# Mon compteur tourne à une vitesse proportionnelle à la puissance instantanée
+
+# https://fr.wikipedia.org/wiki/%C3%89lectricit%C3%A9_domestique#Tension
+# En france, ERDF fourni 230V EFFICACES (=> 207.0727527161344 moyenne)
+
+# raw average: 636207384.4738322 - min: -2147483648 - max: 2147483392
+# average 4806.6W
+
+
+def loop(optrecord, optstats):
+    p = pyaudio.PyAudio()
+
+    print("opened")
+    NSAMPLE = int(RATE * RECORD_SECONDS)
+    stream = p.open(
+            format=FORMAT,
+            channels=1,  # Our ampmeter always returns 0 on the second channel
+            rate=RATE,
+            input=True,
+            input_device_index=DEVICE)
+
+    structformat = '<' + STRUCTFORMAT * NSAMPLE
+    while(True):
+        try:
+            total = 0
+            minvalue = 0
+            maxvalue = 0
+            data = stream.read(NSAMPLE, exception_on_overflow=False)
+            values = struct.unpack(structformat, data)
+            # print(values)
+            # for x in range(100):
+            #    print('**{:04x}**{}**'.format(values[x], values[x]))
+            for value in values:
+                if value > 0:
+                    total += value
+                else:
+                    total -= value
+                if value > maxvalue:
+                    maxvalue = value
+                if value < minvalue:
+                    minvalue = value
+            avg = float(total) / NSAMPLE
+            if optstats:
+                print("raw average: {} - min: {} - max: {}".format(
+                    avg, minvalue, maxvalue))
+            watts = avg / VOLUME_CONSTANT
+            print("average {:.1f}W  ".format(watts), end='\r')
+            if optrecord:
+                os.system(
+                        "rrdtool update --daemon /var/run/rrdcached.sock"
+                        " /var/lib/rrdcached/db/power.rrd {}:{}".format(
+                            time.time(), watts))
+        except KeyboardInterrupt:
+            print("Received KeyboardInterrupt: exiting")
+            break
+
+    stream.stop_stream()
+    stream.close()
+    p.terminate()
+
+
+def main():
+    import argparse
+
+    parser = argparse.ArgumentParser(description='Ampemeter processing')
+    parser.add_argument(
+            '--stats',
+            action='store_true',
+            default=False,
+            help='Dump recording level stats for every chunk',
+            )
+    parser.add_argument(
+            '--norecord',
+            action='store_false',
+            default=True,
+            help='Disable recording in RRD file',
+            dest='record',
+            )
+    args = parser.parse_args()
+
+    if not args.record:
+        print('Recording disabled.')
+
+    loop(optrecord=args.record, optstats=args.stats)
+
 
+if __name__ == '__main__':
+    main()