From: Roman Bazalevsky Date: Tue, 19 May 2015 14:04:08 +0000 (+0300) Subject: Merge commit '2545d27aacfe57c8f26fccfd45e382fbf5c111ac' X-Git-Url: https://git.rvb.name/weathermon.git/commitdiff_plain/769d0bd71b19b467c195838379a379e0e2d69c2b?hp=6f6f38ad845e089ef732873cfcf8e321d8cc1e38 Merge commit '2545d27aacfe57c8f26fccfd45e382fbf5c111ac' Conflicts: web/config_local.php --- diff --git a/Weather_Station.ino b/Weather_Station.ino index 8ba7cee..9358d3d 100644 --- a/Weather_Station.ino +++ b/Weather_Station.ino @@ -71,6 +71,8 @@ SFE_BMP180 pressure; // DHT object for humidity sensor DHT dht; + +#define CO2_PIN A1 #define DHT_PIN 4 #define GAS_PIN A0 #define START_DELAY 20000 @@ -78,6 +80,48 @@ DHT dht; byte HasBaro; +#define READ_SAMPLE_INTERVAL 50 +#define READ_SAMPLE_TIMES 5 + +#define MQ135_RES 1000 + +float MQRead(int mq_pin) +{ + + int i; + float rs=0; + float rr; + + for (i=0;i -#include -#include - -// DHT11 and BMP085 wired sensors -dht DHT; -BMP085 bmp; - -// Humidity sensor at pin 4 -#define DHT11PIN 5 -int sensorPin = 0; -#define DEBUG - -// LED pins -#define REDPIN 11 -#define GREENPIN 12 - -// Read data from 433MHz receiver on digital pin 3 -#define RF_IN 4 -// For better efficiency, the port is read directly -// the following two lines should be changed appropriately -// if the line above is changed. -#define RF_IN_RAW PIND4 -#define RF_IN_PIN PIND - -// Port that is hooked to LED to indicate a packet has been received - -#define COUNTER_RATE 3200-1 // 16,000,000Hz / 3200 = 5000 interrupts per second, ie. 200us between interrupts -// 1 is indicated by 500uS pulse -// wh2_accept from 2 = 400us to 3 = 600us -#define IS_HI_PULSE(interval) (interval >= 2 && interval <= 3) -// 0 is indicated by ~1500us pulse -// wh2_accept from 7 = 1400us to 8 = 1600us -#define IS_LOW_PULSE(interval) (interval >= 7 && interval <= 8) -// worst case packet length -// 6 bytes x 8 bits x (1.5 + 1) = 120ms; 120ms = 200us x 600 -#define HAS_TIMED_OUT(interval) (interval > 600) -// we expect 1ms of idle time between pulses -// so if our pulse hasn't arrived by 1.2ms, reset the wh2_packet_state machine -// 6 x 200us = 1.2ms -#define IDLE_HAS_TIMED_OUT(interval) (interval > 6) -// our expected pulse should arrive after 1ms -// we'll wh2_accept it if it arrives after -// 4 x 200us = 800us -#define IDLE_PERIOD_DONE(interval) (interval >= 4) -// Shorthand for tests -//#define RF_HI (digitalRead(RF_IN) == HIGH) -//#define RF_LOW (digitalRead(RF_IN) == LOW) -#define RF_HI (bit_is_set(RF_IN_PIN, RF_IN_RAW)) -#define RF_LOW (bit_is_clear(RF_IN_PIN, RF_IN_RAW)) - -// wh2_flags -#define GOT_PULSE 0x01 -#define LOGIC_HI 0x02 -volatile byte wh2_flags = 0; -volatile byte wh2_packet_state = 0; -volatile int wh2_timeout = 0; -byte wh2_packet[5]; -byte wh2_calculated_crc; - - -#ifdef DEBUG -byte printed = 0; -#endif - -ISR(TIMER1_COMPA_vect) -{ - static byte sampling_state = 0; - static byte count; - static boolean was_low = false; - - switch(sampling_state) { - case 0: // waiting - wh2_packet_state = 0; - if (RF_HI) { - if (was_low) { - count = 0; - sampling_state = 1; - was_low = false; - } - } else { - was_low = true; - } - break; - case 1: // acquiring first pulse - count++; - // end of first pulse - if (RF_LOW) { - if (IS_HI_PULSE(count)) { - wh2_flags = GOT_PULSE | LOGIC_HI; - sampling_state = 2; - count = 0; - } else if (IS_LOW_PULSE(count)) { - wh2_flags = GOT_PULSE; // logic low - sampling_state = 2; - count = 0; - } else { - sampling_state = 0; - } - } - break; - case 2: // observe 1ms of idle time - count++; - if (RF_HI) { - if (IDLE_HAS_TIMED_OUT(count)) { - sampling_state = 0; - } else if (IDLE_PERIOD_DONE(count)) { - sampling_state = 1; - count = 0; - } - } - break; - } - - if (wh2_timeout > 0) { - wh2_timeout++; - if (HAS_TIMED_OUT(wh2_timeout)) { - wh2_packet_state = 0; - wh2_timeout = 0; -#ifdef DEBUG - if (printed) { - Serial1.println(); - printed=0; - } -#endif - } - } -} - -void setup() { - - Serial1.begin(115200); // Set the baud. - - // Wait for U-boot to finish startup. Consume all bytes until we are done. - do { - while (Serial1.available() > 0) { - Serial1.read(); - } - - delay(1000); - } while (Serial1.available()>0); - - Serial1.begin(57600); - Serial1.println(); - Serial1.println("STATUS:STARTING"); - - bmp.begin(); - - pinMode(REDPIN,OUTPUT); - pinMode(GREENPIN,OUTPUT); - - pinMode(RF_IN, INPUT); - digitalWrite(RF_IN,HIGH); - - TCCR1A = 0x00; - TCCR1B = 0x09; - TCCR1C = 0x00; - OCR1A = COUNTER_RATE; - TIMSK1 = 0x02; - - // enable interrupts - sei(); -} - -unsigned long previousMillis = 0; -unsigned long indoor_interval = 60000; -unsigned long outdoor_interval = 45000; -unsigned long previousIndoor = 0; -unsigned long previousOutdoor = 0; - -float temperature; -float pressure; - -void loop() { - unsigned long now; - int gas = 0; - byte i; - - now = millis(); - - if (wh2_flags) { - if (wh2_accept()) { - // calculate the CRC - wh2_calculate_crc(); - - if (wh2_valid()) { - - Serial1.println(); - Serial1.print("SENSOR:TYPE=OUTDOOR,"); - - Serial1.print("ID="); - Serial1.print(wh2_sensor_id(), HEX); - - Serial1.print(",HUMIDITY="); - Serial1.print(wh2_humidity(), DEC); - - Serial1.print(",TEMPERATURE="); - Serial1.println(format_temp(wh2_temperature())); - - previousOutdoor = now; - digitalWrite(REDPIN,HIGH); - - } else { - - Serial1.println(); - Serial1.println("ERROR:OUTDOOR"); - previousOutdoor = now; - digitalWrite(REDPIN,LOW); - - } - - } - wh2_flags = 0x00; - } - - if ((unsigned long)(now - previousMillis) >= indoor_interval) { - - previousMillis = now; - - int chk = DHT.read11(DHT11PIN); - - if (chk==0) { - - Serial1.println(); - Serial1.print("SENSOR:TYPE=INDOOR,"); - Serial1.print("HUMIDITY="); - Serial1.print(DHT.humidity); - Serial1.print(",TEMPERATURE="); - Serial1.print(DHT.temperature); - - previousIndoor = now; - digitalWrite(GREENPIN,HIGH); - - - } else { - - Serial1.println(); - Serial1.println("ERROR:INDOOR"); - previousIndoor = now; - digitalWrite(GREENPIN,LOW); - - } - - pressure=bmp.readPressure(); - temperature=bmp.readTemperature(); - Serial1.println(); - Serial1.print("SENSOR:TYPE=BARO,"); - Serial1.print("PRESSURE="); - Serial1.print(pressure); - Serial1.print(",TEMPERATURE="); - Serial1.println(temperature); - - gas = analogRead(sensorPin); // Получаем значения из датчика - Serial1.print("SENSOR:TYPE=GAS,VALUE="); - Serial1.println(gas); // Пишем в серийный порт - - } - - if ((unsigned long)(now - previousIndoor) > indoor_interval*10) { - - Serial1.println(); - Serial1.println("ERROR:INDOOR TIMEOUT"); - previousIndoor = now; - digitalWrite(GREENPIN,LOW); - - } - - if ((unsigned long)(now - previousOutdoor) > outdoor_interval*10) { - - Serial1.println(); - Serial1.println("ERROR:OUTDOOR TIMEOUT"); - previousOutdoor = now; - digitalWrite(REDPIN,LOW); - - } - - -} - - -// processes new pulse -boolean wh2_accept() -{ - static byte packet_no, bit_no, history; - - // reset if in initial wh2_packet_state - if(wh2_packet_state == 0) { - // should history be 0, does it matter? - history = 0xFF; - wh2_packet_state = 1; - // enable wh2_timeout - wh2_timeout = 1; - } // fall thru to wh2_packet_state one - - // acquire preamble - if (wh2_packet_state == 1) { - // shift history right and store new value - history <<= 1; - // store a 1 if required (right shift along will store a 0) - if (wh2_flags & LOGIC_HI) { - history |= 0x01; - } - // check if we have a valid start of frame - // xxxxx110 - if ((history & B00000111) == B00000110) { - // need to clear packet, and counters - packet_no = 0; - // start at 1 becuase only need to acquire 7 bits for first packet byte. - bit_no = 1; - wh2_packet[0] = wh2_packet[1] = wh2_packet[2] = wh2_packet[3] = wh2_packet[4] = 0; - // we've acquired the preamble - wh2_packet_state = 2; - } - return false; - } - // acquire packet - if (wh2_packet_state == 2) { - - wh2_packet[packet_no] <<= 1; - if (wh2_flags & LOGIC_HI) { - wh2_packet[packet_no] |= 0x01; -#ifdef DEBUG - Serial1.print('1'); - printed=1; - } else { - Serial1.print('0'); - printed=1; -#endif - } - - bit_no ++; - if(bit_no > 7) { - bit_no = 0; - packet_no ++; - } - - if (packet_no > 4) { - // start the sampling process from scratch - wh2_packet_state = 0; - // clear wh2_timeout - wh2_timeout = 0; - return true; - } - } - return false; -} - - -void wh2_calculate_crc() -{ - wh2_calculated_crc = crc8(wh2_packet, 4); -} - -bool wh2_valid() -{ - return (wh2_calculated_crc == wh2_packet[4]); -} - -int wh2_sensor_id() -{ - return (wh2_packet[0] << 4) + (wh2_packet[1] >> 4); -} - -byte wh2_humidity() -{ - return wh2_packet[3]; -} - -/* Temperature in deci-degrees. e.g. 251 = 25.1 */ -int wh2_temperature() -{ - int temperature; - temperature = ((wh2_packet[1] & B00000111) << 8) + wh2_packet[2]; - // make negative - if (wh2_packet[1] & B00001000) { - temperature = -temperature; - } - return temperature; -} - -String format_temp(int temperature) -{ - byte whole, partial; - String s; - s = String(); - if (temperature<0) { - temperature = -temperature; - s += String('-'); - } - - whole = temperature / 10; - partial = temperature - (whole*10); - - s += String(whole, DEC); - s += '.'; - s += String(partial, DEC); - - return s; - -} - -uint8_t crc8( uint8_t *addr, uint8_t len) -{ - uint8_t crc = 0; - - // Indicated changes are from reference CRC-8 function in OneWire library - while (len--) { - uint8_t inbyte = *addr++; - for (uint8_t i = 8; i; i--) { - uint8_t mix = (crc ^ inbyte) & 0x80; // changed from & 0x01 - crc <<= 1; // changed from right shift - if (mix) crc ^= 0x31;// changed from 0x8C; - inbyte <<= 1; // changed from right shift - } - } - return crc; -} - - - - - - - - - diff --git a/weathermon b/weathermon deleted file mode 100755 index 68798a1..0000000 --- a/weathermon +++ /dev/null @@ -1,414 +0,0 @@ -#!/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 - 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 = ser.readline() - return line.strip() - except KeyboardInterrupt: - return "<>" - finally: - timeout_timer.cancel() - -def read_loop(ser,callback): - - global proc - - while True: - - try: - line=read_port(ser) - if line=="<>": - print "Reopening port..." - ser.close() - if proc: - print "Terminating process..." - proc.terminate() - sleep(5) - 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() - -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') - main()