greenhousino/sensor433/src/main.cpp

283 lines
6.0 KiB
C++

/*
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 <Arduino.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <util/delay.h>
// 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 <RH_ASK.h>
// 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;
}