Cleanup
[ampy.git] / run.py
1 #!/usr/bin/python3
2 """
3 PyAudio example: Record a few seconds of audio and save to a WAVE
4 file.
5 """
6
7 import os
8 import struct
9 import time
10
11 import pyaudio
12
13 FORMAT = pyaudio.paInt32  # Format
14 STRUCTFORMAT = 'i'  # Format for python struct module
15 DEVICE = 5  # which alsa decive to read
16 RATE = 44100
17 RECORD_SECONDS = 0.5
18
19 VOLUME_CONSTANT = 132360.98315789475
20
21 # https://www.actutem.com/valeur-crete-moyenne-et-efficace-dune-tension-ac/
22 # math.pi/math.sqrt(2)/2 = 1.1107207345395915
23
24 # Pour 30 A à 230V ( 6900 W )
25 # abs(Sndmax) = 2147483520
26 # Sndavg = 2147483520/math.pi = 683565234.8327662
27 # Sndeff = 683565234.8327662 * 1.1107207345395915 = 759250079.7391784
28
29 # https://fr.wikipedia.org/wiki/Compteur_%C3%A9lectrique
30 # Mon compteur tourne à une vitesse proportionnelle à la puissance instantanée
31
32 # https://fr.wikipedia.org/wiki/%C3%89lectricit%C3%A9_domestique#Tension
33 # En france, ERDF fourni 230V EFFICACES (=> 207.0727527161344 moyenne)
34
35 # raw average: 636207384.4738322 - min: -2147483648 - max: 2147483392
36 # average 4806.6W
37
38
39 def loop(optrecord, optstats):
40     p = pyaudio.PyAudio()
41
42     print("opened")
43     NSAMPLE = int(RATE * RECORD_SECONDS)
44     stream = p.open(
45             format=FORMAT,
46             channels=1,  # Our ampmeter always returns 0 on the second channel
47             rate=RATE,
48             input=True,
49             input_device_index=DEVICE)
50
51     structformat = '<' + STRUCTFORMAT * NSAMPLE
52     while(True):
53         try:
54             total = 0
55             minvalue = 0
56             maxvalue = 0
57             data = stream.read(NSAMPLE, exception_on_overflow=False)
58             values = struct.unpack(structformat, data)
59             # print(values)
60             # for x in range(100):
61             #    print('**{:04x}**{}**'.format(values[x], values[x]))
62             for value in values:
63                 if value > 0:
64                     total += value
65                 else:
66                     total -= value
67                 if value > maxvalue:
68                     maxvalue = value
69                 if value < minvalue:
70                     minvalue = value
71             avg = float(total) / NSAMPLE
72             if optstats:
73                 print("raw average: {} - min: {} - max: {}".format(
74                     avg, minvalue, maxvalue))
75             watts = avg / VOLUME_CONSTANT
76             print("average {:.1f}W  ".format(watts), end='\r')
77             if optrecord:
78                 os.system(
79                         "rrdtool update --daemon /var/run/rrdcached.sock"
80                         " /var/lib/rrdcached/db/power.rrd {}:{}".format(
81                             time.time(), watts))
82         except KeyboardInterrupt:
83             print("Received KeyboardInterrupt: exiting")
84             break
85
86     stream.stop_stream()
87     stream.close()
88     p.terminate()
89
90
91 def main():
92     import argparse
93
94     parser = argparse.ArgumentParser(description='Ampemeter processing')
95     parser.add_argument(
96             '--stats',
97             action='store_true',
98             default=False,
99             help='Dump recording level stats for every chunk',
100             )
101     parser.add_argument(
102             '--norecord',
103             action='store_false',
104             default=True,
105             help='Disable recording in RRD file',
106             dest='record',
107             )
108     args = parser.parse_args()
109
110     if not args.record:
111         print('Recording disabled.')
112
113     loop(optrecord=args.record, optstats=args.stats)
114
115
116 if __name__ == '__main__':
117     main()