pyP2Monitor  1.0.0
Monitor a P2 furnace activity reading data on serial port
 All Data Structures Namespaces Functions Variables Groups Pages
pyP2SerialMon.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-#
3 
4 # Copyright 2013, 2014 Weber Yann, Weber Laurent
5 #
6 # This file is part of pyP2Monitor.
7 #
8 # pyP2Monitor is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # pyP2Monitor is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with pyP2Monitor. If not, see <http://www.gnu.org/licenses/>.
20 #
21 
22 ##@page serialmon Howto use the monitoring programm
23 #
24 # @section smdesc Description
25 # The monitoring programm is used to retrieve and store datas from the furnace using the serial port.
26 # This is done by running the pyP2_monitor executable.
27 #
28 # @section smopt Programm options
29 # There is few important options :
30 # - -p That define the serial port to communicate on ( on GNU/Linux system usually something like /dev/ttyS0 )
31 # - -d That define the name of the sqlite database to store datas in
32 # - -B That tell the programm to fork in background
33 #
34 # To have more informations on possible options run "pyP2_monitor -h"
35 
36 #Python libs import
37 import serial, signal, time, sys, os, traceback
38 import time
39 
40 #pyP2Monitor import
41 import p2com
42 from p2com import *
43 import p2proto
44 from p2proto import *
45 import p2msg
46 from p2msg import *
47 import utils
48 
49 com = None
50 pidfile= ""
51 
52 ##Gentle exit to manage sigint
53 def gentle_exit(signal, frame):
54  logger.critical("signal caught, exiting")
55  #Serial port closing
56  com.stop()
57  os.unlink(pidfile)
58  sys.exit(0)
59 
60 ##"Fork" into background
61 def start_daemon(pidfile):
62  arg = []
63  for e in sys.argv:
64  if e != '-B' and e != '--background': #Deleting background option
65  arg.append(e)
66  logger.debug("Starting background process...")
67  pid = os.spawnv(os.P_NOWAIT,arg[0], arg)
68  fdpid = open(pidfile,"w+")
69  fdpid.write(str(pid))
70  fdpid.close()
71 
72  logger.debug("Background process started. Pid = "+str(pid))
73 
74  return pid
75 
76 
77 signal.signal(signal.SIGINT, gentle_exit)
78 signal.signal(10, gentle_exit)
79 
80 #Argument parse
81 args = utils.argParse('monitor')
82 
83 #Init output (logging and verbosity)
84 utils.initLogging(args['verbosity'], args['log_file'], args['log_level'], args['log_num'], args['log_size'])
85 
86 logger = utils.getLogger()
87 
88 #start background process to start a daemon
89 pidfile = args['pidfile']
90 if args['background']:
91  exit(start_daemon(pidfile))
92 elif args['stop']: #or kill an existing daemon
93  try:
94  pidfd = open(pidfile,"r")
95  pid = int(pidfd.read())
96  os.kill(pid, 10)
97  logger.debug("Sig 10 send to process",pid)
98  except:
99  exit(0)
100  exit(1)
101 
102 
103 #Store all the data's storage method
104 storage = []
105 if args['database'] != None:
106  for c in args['database']:
107  storage.append(('sqlite',c))
108 if args['last_data'] != None:
109  #Testing if this file is openable
110  lfile=open(args['last_data'], "w+")
111  lfile.close()
112  #adding the file to the storage list
113  storage.append(('lastdata',args['last_data']))
114 if args['file'] != None:
115  for c in args['file']:
116  storage.append(('file',c))
117 if args['csv'] != None:
118  for c in args['csv']:
119  storage.append(('csv',c))
120 
121 #Serial port opening
122 com = P2Furn(args['port'])
123 
124 #Running wanted stages
125 for stage in args['stage']:
126  maxretry = 3
127 
128  infinite = False
129 
130  stages = 0
131 
132  if stage == 'all':
133  stages = 7
134  infinite = True
135  elif stage == 'auth':
136  stages = 1
137  elif stage == 'init':
138  stages = 2
139  elif stage == 'data':
140  stages = 3
141 
142  while True:
143  try:
144 
145  #Run auth stage
146  if stages&1:
147  again = 0
148  while again<maxretry:
149  try:
150  com.runAuth(P2Furn.userId(args['user']))
151  again = maxretry+1
152  except p2com.P2ComError as e:
153  if again < maxretry:
154  logger.error("Authentication stage failed : "+str(e))
155  again+=1
156  time.sleep(10*again)
157  else:
158  logger.critical("Authentication stage failed again after "+str(maxretry)+" attempts")
159  raise e
160 
161  #Run initialisation stage
162  if stages&2:
163  again = 0
164  while again<maxretry:
165  try:
166  com.runInit()
167  again = maxretry+1
168  except p2com.P2ComError as e:
169  if again < maxretry:
170  logger.error("Initialisation stage failed : "+str(e))
171  again+=1
172  time.sleep(10*again)
173  else:
174  logger.critical("Initialisation stage failed again after "+str(maxretry)+" attempts")
175  raise e
176 
177  #Run data exchange stage
178  if stages&3:
179  again = 0
180  while again<maxretry:
181  try:
182  com.readData(float(args['data_wait']),storage)
183  again = maxretry+1
184  except p2com.P2ComError as e:
185  if again < maxretry:
186  logger.error("DataReading stage failed : "+str(e))
187  again+=1
188  time.sleep(10*again)
189  else:
190  logger.critical("DataReading stage failed again after "+str(maxretry)+" attempts")
191  raise e
192 
193  except p2com.P2ComError as e: #Catch exception raised by stage failed after maxretry
194  if infinite:
195  logger.error("Running stages failed, closing serial port, waiting 60 seconds and trying again...")
196  com.stop()
197  time.sleep(60)
198  logger.info("Opening serial port again and trying again")
199  com = P2Furn(args['port'])
200  else:
201  raise e
202  except SystemExit:
203  raise
204  except:
205  logger.critical(traceback.format_exc())
206  com.stop()
207  exit(1)
208 
209 #Serial port closing
210 com.stop()