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