/* RadioHead attiny85 DHT22 Weather Station 2021 Stefan Ostermann based on several source from the internetz. Sources: https://git.cryhost.de/crycode/attiny85-radiohead-dht22-weather-sensor/-/tree/master */ // pin with the transistor base (And LED) is connected #define TRANSISTOR_BASE_PIN 4 // blink time for the LED #define LED_TIME 200 // pin of the DHT22 sensor #define DHT_PIN 1 // pin of the soil sensor #define SOIL_PIN A1 // the own RadioHead address #define RH_OWN_ADDR 0xca // 202 // RadioHead bitrate in bit/s #define RH_SPEED 1000 /* define when to wake up 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec */ #define WATCHDOG_WAKEUP 9 // Sleep this many again before waging up. Sleep time in s = WATCHDOG_WAKEUP s * WATCHDOG_SLEEP_FURTHER, e.g. 8*8s = 64s #define WATCHDOG_SLEEP_FURTHER 8 // pins for the radio hardware #define RH_RX_PIN 6 // not used, set to a non-existent pin #define RH_TX_PIN 3 // Transmit Pin #define RH_PTT_PIN 6 // not used, set to a non-existent pin #include #include #include #include // for watchdog wakeup // https://gist.github.com/dwhacks/8055287 #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif // DHT22 lib // not using the current adafruit dht library, because it's too memory intensive #include "dht22.h" dht22 dht; // Configuration, see file config.h.example and rename to config.h. Project specific, do not add to git! #include "config.h" #define RH_BUF_LEN 11 uint8_t rh_buf[RH_BUF_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // reduce the RadioHead max message length to save memory #define RH_ASK_MAX_MESSAGE_LEN RH_BUF_LEN // RadioHead #include // Message Headers: #define MSG_START 0x00 #define MSG_TEMP 0x01 #define MSG_HUMID 0x02 #define MSG_BAT 0x03 #define MSG_SOIL 0x04 #define MSG_HEADER 0x05 #define MSG_ERR 0xee RH_ASK rh_driver(RH_SPEED, RH_RX_PIN, RH_TX_PIN, RH_PTT_PIN); // watchdog flag volatile boolean f_wdt = 1; // temp / humid toggle volatile uint8_t counter = 0; // prototypes: void gotoSleep(void); int getVcc(); void rh_send(uint8_t len); void setup_watchdog(int ii); void system_sleep(); void blink(uint8_t num); void setup() { // setup the LED pin pinMode(TRANSISTOR_BASE_PIN, OUTPUT); pinMode(SOIL_PIN, INPUT); // init the DHT22 dht_init(&dht, DHT_PIN); uint8_t num_blink = 3; if (!rh_driver.init()) { num_blink = 5; } blink(num_blink); // send start message rh_buf[0] = MSG_START; rh_send(1); setup_watchdog(WATCHDOG_WAKEUP); } // main loop void loop() { if (f_wdt) { f_wdt = 0; // turn on the LED and the transistor: digitalWrite(TRANSISTOR_BASE_PIN, HIGH); // temperature and humidity float t = 0; //float is 32bit = 4 byte float h = 0; int soil = 0; long battery = 0; // wait for everything the transistor switched on: delay(50); if (counter % 4 == 0) { rh_buf[0] = MSG_BAT; battery = getVcc(); memcpy(&rh_buf[1], &battery, 4); rh_send(RH_BUF_LEN); } else if (dht_read_data(&dht, &t, &h) == 1) { rh_buf[0] = MSG_HEADER; memcpy(&rh_buf[1], &t, 4); memcpy(&rh_buf[5], &h, 4); soil = analogRead(SOIL_PIN); memcpy(&rh_buf[9], &soil, 2); rh_send(RH_BUF_LEN); } else { // error message blink(4); digitalWrite(TRANSISTOR_BASE_PIN, HIGH); delay(5); rh_buf[0] = MSG_ERR; rh_send(1); } counter++; // turn off the LED and transistor: digitalWrite(TRANSISTOR_BASE_PIN, LOW); // deep sleep for (uint8_t i = 0; i < WATCHDOG_SLEEP_FURTHER; i++) { system_sleep(); // if one of the first loops sleep less long for easyier debugging: if (counter<10) { break; } } } } void blink(uint8_t num) { // blink n times for (uint8_t i = 0; i < num; i++) { digitalWrite(TRANSISTOR_BASE_PIN, HIGH); _delay_ms(LED_TIME); digitalWrite(TRANSISTOR_BASE_PIN, LOW); _delay_ms(LED_TIME); } } // function to send RadioHead messages from the buffer void rh_send(uint8_t len) { rh_driver.send((uint8_t *)rh_buf, len); rh_driver.waitPacketSent(); } ISR(WDT_vect) { f_wdt = 1; // set global flag } /* set system into the sleep state system wakes up when watchdog is timed out */ void system_sleep() { set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here sleep_enable(); sleep_mode(); // System sleeps here sleep_disable(); // System continues execution here when watchdog timed out } /* 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec */ void setup_watchdog(int ii) { byte bb; int ww; if (ii > 9) ii = 9; bb = ii & 7; if (ii > 7) bb |= (1 << 5); bb |= (1 << WDCE); ww = bb; MCUSR &= ~(1 << WDRF); // start timed sequence WDTCR |= (1 << WDCE) | (1 << WDE); // set new watchdog timeout value WDTCR = bb; WDTCR |= _BV(WDIE); } /** From https://github.com/cano64/ArduinoSystemStatus/blob/master/SystemStatus.cpp */ int getVcc() { //reads internal 1V1 reference against VCC #if defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny44__) ADMUX = _BV(MUX5) | _BV(MUX0); // For ATtiny84 #elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) ADMUX = _BV(MUX3) | _BV(MUX2); // For ATtiny85/45 #elif defined(__AVR_ATmega1284P__) ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega1284 #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega328 #endif delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Convert while (bit_is_set(ADCSRA, ADSC)) ; uint8_t low = ADCL; unsigned int val = (ADCH << 8) | low; //discard previous result ADCSRA |= _BV(ADSC); // Convert while (bit_is_set(ADCSRA, ADSC)) ; low = ADCL; val = (ADCH << 8) | low; return ((long)1024 * 1100) / val; }