Pre-release demo version
[ampy.git] / run.py
diff --git a/run.py b/run.py
index c4bbf79ad5f81f17394b7bdac0373cdd98edcf36..edff65e72883ee0666989c1aaf740239b713b5c5 100755 (executable)
--- a/run.py
+++ b/run.py
@@ -9,45 +9,109 @@ import pyaudio
 import wave
 import sys
 import struct
+import time
 
+FORMAT = pyaudio.paInt32  # Format
+STRUCTFORMAT = 'i'  # Format for python struct module
 DEVICE = 3  # which alsa decive to read
-CHUNK = 1024  # how many bytes at a time?
-FORMAT = pyaudio.paInt16  # Format
 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
 
+#amixer -c 1 contents
+# numid=23,iface=MIXER,name='Capture Volume'
+#   ; type=INTEGER,access=rw---R--,values=2,min=0,max=46,step=0
+#   : values=17,17
+#   | dBscale-min=-16.00dB,step=1.00dB,mute=0
+# => Set volume to 18
+
+# 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 power.rrd N:{}".format(watts))
+                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()