-/*
- Updated code for receiving data from WH2 weather station
- This code implements timeouts to make decoding more robust
- Decodes received packets and writes a summary of each packet to the Arduino's
- serial port
- Created by Luc Small on 19 July 2013.
- Released into the public domain.
-*/
-
-#include <dht.h>
-#include <Wire.h>
-#include <BMP085.h>
-
-// DHT11 and BMP085 wired sensors
-dht DHT;
-BMP085 bmp;
-
-// Humidity sensor at pin 4
-#define DHT11PIN 5
-
-#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(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;
-
-
-void loop() {
- unsigned long now;
- 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);
-
- Serial1.println();
- Serial1.print("SENSOR:TYPE=BARO,");
- Serial1.print("PRESSURE=");
- Serial1.print(bmp.readPressure());
- Serial1.print(",TEMPERATURE=");
- Serial1.println(bmp.readTemperature());
-
- previousIndoor = now;
- digitalWrite(GREENPIN,HIGH);
-
- } else {
-
- Serial1.println();
- Serial1.println("ERROR:INDOOR");
- previousIndoor = now;
- digitalWrite(GREENPIN,LOW);
-
- }
-
- }
-
- 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;
-}
-
-
-
-
-
-
-
-
-