#!/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/' baud = 57600 path = None timeout = 5 external_submit_interval = 320 expire_interval = 1200 submit_time = time() submit_queue = {} import MySQLdb import ConfigParser 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): ser = serial.Serial(path,baud,timeout) if ser.portstr: tcflush(ser,TCIOFLUSH); return ser def read_port(ser): line = ser.readline() return line.strip() def read_loop(ser,callback): while True: try: line=read_port(ser) 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(queue): param = { 'ID':"{:X}".format(getnode())} pprint(queue) for sensor in queue: value = submit_queue[sensor]['val'] timestamp = submit_queue[sensor]['timestamp'] digest = md5(sensor).hexdigest()[:18] param[digest] = 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('Content: '+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(queue): url = "http://openweathermap.org/data/post" params = {'name':owm_station, 'lat':owm_lat, 'long':owm_lon} try: try: params['temp'] = queue[owm_temp]['val'] params['pressure'] = queue[owm_pres]['val'] params['humidity'] = queue[owm_humi]['val'] except: return False 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('Content: '+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 purge_queue(): global submit_queue clean = [] for key in submit_queue: if submit_queue[key]['timestamp'] < time()-expire_interval: print_log("Expired value for "+key) clean.append(key) for i in clean: del submit_queue[i] def submit_data(sensor_type,sensor_id,sensor_param,param_value): global submit_time global submit_queue c = database.cursor() c.execute('CALL meteo.submit_value(%s,%s,%s,%s,NULL)', (sensor_type,sensor_id,sensor_param,param_value)) database.commit() submit_queue[sensor_type+'.'+sensor_id+'.'+sensor_param]={'val':param_value,'timestamp':time()} if time()>submit_time+external_submit_interval: if submit_narodmon(submit_queue): if owmuser: submit_owm(submit_queue) print_log('Purging queue...') submit_time=time() purge_queue() 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('=') 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='DEFAULT'; for key in sensor: if sensor[key] is not None: 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) 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() 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 owmuser = cfg.get("openweathermap","user") owmpasswd = cfg.get("openweathermap",'passwd') 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') reconnect() except: print_log("Cannot intialize system") exit() if __name__ == "__main__": import sys reload(sys) sys.setdefaultencoding('utf-8') main()