+#!/usr/bin/python
+
+import serial
+
+from os import listdir,system
+from os.path import isfile, join
+
+from pprint import pprint
+
+from termios import tcflush, TCIOFLUSH
+
+from time import sleep,time
+
+from uuid import getnode
+
+from hashlib import md5
+
+import socket
+
+import sys,traceback
+
+import pycurl
+from urllib import urlencode
+from StringIO import StringIO
+
+searchpath = '/dev/serial/by-id/'
+path = None
+baud = None
+timeout = None
+
+proc = None
+
+external_submit_interval = 320
+owm_submit_interval = 320
+expire_interval = 1200
+submit_time = time()
+submit_time_owm = time()
+
+import MySQLdb
+import ConfigParser
+
+import thread
+from threading import Timer
+
+def find_port():
+
+ global serial_num
+ global path
+
+ files = listdir(searchpath)
+ for f in files:
+ if serialnum in f:
+ return join(searchpath,f)
+ return None
+
+def open_port(path):
+
+ global proc
+
+ print "Opening path "+path
+
+ if path == "-":
+ return sys.stdin
+
+ if path[0] == "=":
+ import subprocess
+ sleep(3)
+ command=path[1:]
+ try:
+ command,args=command.split(' ',1)
+ proc = subprocess.Popen([command,args],stdout=subprocess.PIPE)
+ except:
+ proc = subprocess.Popen([command],stdout=subprocess.PIPE)
+ import subprocess
+ return proc.stdout
+
+ ser = serial.Serial(path,baud,timeout=timeout)
+ if ser.portstr:
+ tcflush(ser,TCIOFLUSH);
+ return ser
+
+def read_port(ser):
+
+ try:
+ timeout_timer = Timer(timeout, thread.interrupt_main)
+ timeout_timer.start()
+
+ line=''
+ while line=='':
+ line = ser.readline()
+ line = line.strip()
+
+ return line
+
+ except KeyboardInterrupt:
+ return "<<TIMEOUT>>"
+ finally:
+ timeout_timer.cancel()
+
+def read_loop(ser,callback):
+
+ global proc
+
+ while True:
+
+ try:
+ line=read_port(ser)
+ if line=="<<TIMEOUT>>":
+ print "Reopening port..."
+ print line
+ ser.close()
+ if proc:
+ try:
+ print "Terminating process..."
+ proc.terminate()
+ sleep(5)
+ finally:
+ None
+ ser=open_port(path)
+ if line:
+ callback(line)
+ except KeyboardInterrupt:
+ break
+ finally:
+ None
+
+def print_log(str):
+ global logging
+ print str
+ if logging == "on":
+ system("logger -t weathermon \""+str+"\"")
+
+def submit_narodmon():
+
+ param = { 'ID':devid }
+
+ c = database.cursor()
+ c.execute(
+ '''
+ select nm_id,value from
+ (
+ SELECT sensor_id,parameter_id,max(timestamp) timestamp,round(avg(value),1) value FROM meteo.sensor_values
+ where
+ timestamp>=date_add(now(), INTERVAL -300 SECOND)
+ group by sensor_id,parameter_id
+ ) v,meteo.ext_sensors e
+ where v.sensor_id=e.sensor_id and v.parameter_id=e.param_id
+ and nm_id is not null
+ '''
+ )
+
+ queue=c.fetchall()
+
+ pprint(queue)
+
+ for (sensor,value) in queue:
+ param[sensor] = value
+ pprint (param)
+
+ url = "http://narodmon.ru/post.php"
+
+ try:
+
+ response_buffer = StringIO()
+ curl = pycurl.Curl()
+
+ curl.setopt(curl.URL, url)
+ curl.setopt(curl.WRITEFUNCTION, response_buffer.write)
+ curl.setopt(curl.POST, 1)
+ curl.setopt(curl.POSTFIELDS, urlencode(param))
+
+ curl.perform()
+ curl.close()
+
+ response_value = response_buffer.getvalue()
+
+ print_log('Narodmon response: '+response_value)
+
+ return True
+
+ except:
+
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ traceback.print_tb(exc_traceback, limit=1, file=sys.stdout)
+ traceback.print_exception(exc_type, exc_value, exc_traceback,
+ limit=2, file=sys.stdout)
+ return False
+
+def submit_owm():
+
+ url = "http://openweathermap.org/data/post"
+ params = {'name':owm_station, 'lat':owm_lat, 'long':owm_lon}
+
+ c = database.cursor()
+ c.execute(
+ '''
+ select owm_id,value from
+ (
+ SELECT sensor_id,parameter_id,max(timestamp) timestamp,round(avg(value),1) value FROM meteo.sensor_values
+ where
+ timestamp>=date_add(now(), INTERVAL -300 SECOND)
+ group by sensor_id,parameter_id
+ ) v,meteo.ext_sensors e
+ where v.sensor_id=e.sensor_id and v.parameter_id=e.param_id
+ and owm_id is not null
+ '''
+ )
+
+ queue=c.fetchall()
+
+ pprint(queue)
+
+ for (sensor,value) in queue:
+ params[sensor]=value
+ pprint (params)
+
+ try:
+
+ response_buffer = StringIO()
+ curl = pycurl.Curl()
+
+ curl.setopt(curl.URL, url)
+ curl.setopt(curl.USERPWD, '%s:%s' % (owmuser, owmpasswd))
+ curl.setopt(curl.WRITEFUNCTION, response_buffer.write)
+ curl.setopt(curl.POST, 1)
+ curl.setopt(curl.POSTFIELDS, urlencode(params))
+
+ curl.perform()
+ curl.close()
+
+ response_value = response_buffer.getvalue()
+
+ print_log('Openweathermap response: '+response_value)
+
+ return True
+
+ except:
+
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ traceback.print_tb(exc_traceback, limit=1, file=sys.stdout)
+ traceback.print_exception(exc_type, exc_value, exc_traceback,
+ limit=2, file=sys.stdout)
+ return False
+
+def submit_data(sensor_type,sensor_id,sensor_param,param_value):
+ global submit_time
+ global submit_time_owm
+ global external_submit_interval
+ global owm_submit_interval
+ c = database.cursor()
+ c.execute('CALL meteo.submit_value(%s,%s,%s,%s,NULL)', (sensor_type,sensor_id,sensor_param,param_value))
+ database.commit()
+ if narmon=='on' and time()>submit_time+external_submit_interval:
+ submit_narodmon()
+ submit_time=time()
+ if owmuser and time()>submit_time_owm+owm_submit_interval:
+ submit_owm()
+ submit_time_owm=time()
+
+def process_str(str):
+ print_log("Received: "+str)
+ try:
+ msg_type, msg_body = str.split(':')
+ except:
+ return
+ try:
+ if msg_type == 'STATUS':
+ print_log('Status: '+msg_body)
+ elif msg_type == 'ERROR':
+ print_log('Error: '+ msg_body)
+ elif msg_type == 'SENSOR':
+ sens = msg_body.split(',')
+ sensor = {}
+ sensor_type = None
+ sensor_id = None
+ for rec in sens:
+ key,value = rec.split('=')
+ value=value.strip()
+ if len(value)>0:
+ if key == 'TYPE':
+ sensor_type = value
+ elif key == 'ID':
+ sensor_id = value
+ else:
+ sensor[key] = value
+ if sensor_type:
+ if not sensor_id:
+ sensor_id=devid;
+ for key in sensor:
+ if sensor[key]:
+ print_log('Type = '+sensor_type+', ID = '+sensor_id+', Param = '+key+', Value = '+sensor[key])
+ submit_data(sensor_type,sensor_id,key,sensor[key])
+ else:
+ print_log('Error: got empty parameter value for '+sensor_type+'.'+sensor_id+'.'+key)
+ elif msg_type == "ALARM":
+ alarm = msg_body.split(',')
+ device_type = None
+ device_id = None
+ for rec in alarm:
+ key,value = rec.split('=')
+ value=value.strip()
+ if len(value)>0:
+ if key == 'TYPE':
+ device_type = value
+ if key == 'ID':
+ device_id = value
+ if device_type:
+ if not device_id:
+ device_id=devid;
+ print_log("Alarm: Type = "+device_type+", ID = "+device_id)
+ if alarm_script:
+ try:
+ proc = subprocess.Popen([alarm_script,device_type,device_id,msg_body])
+ except:
+ print_log("Failed to execute alarm script")
+ except:
+ print_log('Exception processing...')
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ traceback.print_tb(exc_traceback, limit=1, file=sys.stdout)
+ traceback.print_exception(exc_type, exc_value, exc_traceback,
+ limit=5, file=sys.stdout)
+ try:
+ database.close()
+ except:
+ None
+ reconnect()
+
+def weather_mon():
+
+ global path
+
+ if path is None:
+ path = find_port()
+ ser = open_port(path)
+ read_loop(ser,process_str)
+
+def reconnect():
+
+ connected = False
+
+ while not connected:
+
+ try:
+
+ global database
+ database = MySQLdb.connect(host=dbhost,user=dbuser,passwd=dbpasswd,use_unicode=True,connect_timeout=10)
+ database.set_character_set('utf8')
+ c = database.cursor()
+ c.execute('SET NAMES utf8;')
+ print_log("Database connected...")
+ connected = True
+
+ except:
+
+ print_log("Error connecting database")
+ sleep(30)
+
+def main():
+ weather_mon()
+
+def init():
+
+ global dbhost,dbuser,dbpasswd,path,serialnum,logging;
+ global timeout,baud,narmon,devid;
+ global owmuser,owmpasswd,owm_temp,owm_pres,owm_humi,owm_lat,owm_lon,owm_station;
+ global alarm_script;
+
+ try:
+
+ cfg = ConfigParser.RawConfigParser(allow_no_value=True)
+ cfg.readfp(open('/etc/weathermon.conf'))
+ dbhost = cfg.get("mysql","host")
+ dbuser = cfg.get("mysql","user")
+ dbpasswd = cfg.get("mysql","passwd")
+ try:
+ path = cfg.get("serial","port");
+ except:
+ path = None
+ try:
+ serialnum = cfg.get("serial","id")
+ except:
+ serialnum = None
+ try:
+ logging = cfg.get("logging","enabled")
+ except:
+ logging = None
+ try:
+ timeout = int(cfg.get("serial","timeout"))
+ except:
+ timeout = 120
+ try:
+ baud = int(cfg.get("serial","baud"))
+ except:
+ baud = 57600
+ try:
+ narmon = cfg.get("narodmon","enable")
+ except:
+ narmon = 'off'
+ try:
+ devid = cfg.get("narodmon","devid")
+ except:
+ devid = "{:0>12X}".format(getnode())
+ try:
+ owmuser = cfg.get("openweathermap","user")
+ owmpasswd = cfg.get("openweathermap",'passwd')
+ except:
+ owmuser = None
+ if owmuser:
+ owm_temp = cfg.get("openweathermap",'temp')
+ owm_pres = cfg.get("openweathermap",'pres')
+ owm_humi = cfg.get("openweathermap",'humi')
+ owm_lat = cfg.get("openweathermap",'lat')
+ owm_lon = cfg.get("openweathermap",'lon')
+ owm_station = cfg.get("openweathermap",'station')
+ try:
+ alarm_script = cfg.get("alarm","exec")
+ import subprocess
+ except:
+ alarm_script = None
+
+ reconnect()
+
+ except:
+
+ print_log("Cannot intialize system")
+ exit()
+
+if __name__ == "__main__":
+ import sys
+ reload(sys)
+ sys.setdefaultencoding('utf-8')
+ init()
+ main()