Hi!
I built a mysensors-datalogger that does not need a controller. The reason for this is that I wanted to log some temperature-data at my office which has a strict IT-security policy and would not allow any network based controller like rasperry pi or vera.
This is what it looks like:
I used the following hardware:
- Arduino Mega 2560 clone (atmega328 has not enough flash for this project)
- oled-display based on sh1106 chipset
- rtc based on DS1302 (would not recommend, but had this one available)
- micro-SD breakout board
- NRF24L01 module
- DHT22 temperature and humidity senosr
- DS18B20 temperature sensor (waterproof)
- some buttons
It is possible to deactivate most of the hardware-pieces in the software. If the RTC has an error or is deactivated by hand it falls back to software RTC.
For powering the NRF24L01 I used the 3.3V regulator of the micro-SD breakout as the mega2560 has a very weak regulator.
Basically the software continuously fetches the onboard sensors and waits for radio signals. Every 5 minutes it writes all available values to the SD-Card.
The mysensors-support is very basic. Currently it only supports up to 6 temperature sensors with one temperature and battery reading each.
Here is the code:
/*
Weatherstation-"Gateway" (Stand-alone)
Created by Florian Heinze
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
#include <U8glib.h>
#include <SPI.h>
#include "SD.h"
#include <MySensor.h>
#include <MyGateway.h>
#include <stdarg.h>
#include <DHT.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1302RTC.h>
#include <EEPROM.h>
const uint8_t ARROW[] U8G_PROGMEM = {
B00000000,
B00001100,
B00000110,
B11111111,
B11111111,
B00000110,
B00001100,
B00000000
};
/*
* PIN-definitions
*/
const int DHT_BUS = A9;
const int ONE_WIRE_BUS = 25;
const int ONE_WIRE_VCC = 23;
const int ONE_WIRE_GND = 27;
const int NRF_CE_PIN = 30;
const int NRF_CS_PIN = 36;
const int SD_CS_PIN = 12;
const int SD_MISO_PIN = 9;
const int SD_MOSI_PIN = 10;
const int SD_SCK_PIN = 11;
const int DISP_CS_PIN = A4;
const int DISP_DC_PIN = A3;
const int DISP_RES_PIN = A2;
const int DISP_SCK_PIN = A0;
const int DISP_MOSI_PIN = A1;
const int RTC_SCK_PIN = 16;
const int RTC_DAT_PIN = 15;
const int RTC_RST_PIN = 14;
const int BUTTON_RIGHT_PIN = 4;
const int BUTTON_LEFT_PIN = 5;
const int BUTTON_UP_PIN = 6;
const int BUTTON_DOWN_PIN = 3;
const int BUTTON_ENTER_PIN = 7;
//Variables for buttons
boolean right = false;
boolean left = false;
boolean up = false;
boolean down = false;
boolean enter = false;
boolean lastright = false;
boolean lastleft = false;
boolean lastup = false;
boolean lastdown = false;
boolean lastenter = false;
const unsigned long DEBOUNCE_DELAY = 10;
unsigned long debouncetime = 0;
unsigned long lastSDWrite = 0;
//Channel for RF
const int RF24_CUST_CHANNEL = 50;
//EEPROM-addreses. start at 512 so it doesnt collide with mysensors.
const int START_EEPROM_ADR = 512;
const int DHT_EEPROM_ADR = START_EEPROM_ADR;
const int ONEWIRE_EEPROM_ADR = START_EEPROM_ADR + 1;
const int RTC_EEPROM_ADR = START_EEPROM_ADR + 2;
const int NRF_EEPROM_ADR = START_EEPROM_ADR + 3;
const int SD_EEPROM_ADR = START_EEPROM_ADR + 4;
//Filenames
#define MYS_LOG "myslog.txt"
#define DATA_LOG "datalog.txt"
const unsigned int WRITE_MINUTE = 5;
//status of hardware
typedef enum {OFF = 0, ERR, ON} hw_stat_t;
hw_stat_t dht_stat;
hw_stat_t onewire_stat;
hw_stat_t rtc_stat;
hw_stat_t nrf_stat; //no ERR state
hw_stat_t sd_stat;
//used for rtc
time_t t = 0;
boolean clock_set = false;
enum {DAY, MONTH, YEAR, HOUR, MINUTE, SECOND} set_digit = DAY;
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
static const uint8_t monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // API starts months from 1, this array starts from 0
//state of HW-page
enum {DHT_22 = 0, DS18B22, RTC, NRF, SD_CARD} hw_page_stat = DHT_22;
//state of display
enum {PAGE1, PAGE2, PAGE3, PAGE4, PAGE5, DIAGRAM, CLOCK, HW_SET} dispstat = PAGE1;
//max number of mysensors
const int MYS_MAX_SENSORS = 6;
//variables for sensors
long lastDHTTime;
long lastOnewireTime;
float tempDHT = 0;
float humDHT = 0;
float tempOnewire = 0;
float tempMyS[MYS_MAX_SENSORS] = {0};//temp of mysensors
time_t lastReadMyS[MYS_MAX_SENSORS] = {0};//last time the mysensors are read
uint8_t battMyS[MYS_MAX_SENSORS] = {0};//battery of mysensors
//used for the diagram
float diagram[128];
boolean diagramRead = false;
boolean diagramScroll = false;
boolean linesUpdate = false;
unsigned long diagramStart = 1;
unsigned long lines = 0;
uint8_t numDiagram = 1;
const int BOT_PXL = 64;
const int TOP_PXL = 0;
boolean dispOnewire = false;
//objects for hardware: temperature-sensors
DHT dht;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
//rtc
DS1302RTC rtc(RTC_RST_PIN, RTC_DAT_PIN, RTC_SCK_PIN);
//display
U8GLIB_SH1106_128X64 u8g(DISP_SCK_PIN, DISP_MOSI_PIN, DISP_CS_PIN, DISP_DC_PIN, DISP_RES_PIN);
//mysensors
MyGateway gw(NRF_CE_PIN, NRF_CS_PIN);
//setup-routine of dht
void setup_dht() {
dht.setup(DHT_BUS);
lastDHTTime = millis();
if (dht.getStatus() == DHT::ERROR_NONE) dht_stat = ON; //check for error
else dht_stat = ERR;
}
//setup routine of onewire
void setup_onewire() {
sensors.begin();
sensors.setWaitForConversion(false);
sensors.requestTemperatures();
if (sensors.getDeviceCount() == 1) onewire_stat = ON; //check for error
else onewire_stat = ERR;
lastOnewireTime = millis();
}
//setup rtc
void setup_rtc() {
if (rtc.get() == 0) //check for error
{
rtc_stat = ERR;
}
else
{
rtc_stat = ON;
setSyncProvider(rtc.get); //rtc is set up as sync provider. normal time comes from internal clock.
}
}
//setup for sd-card
void setup_sd() {
if (SD.begin(SD_CS_PIN, SD_MOSI_PIN, SD_MISO_PIN, SD_SCK_PIN)) {//start and check for error
sd_stat = ON;
if (!SD.exists(DATA_LOG)) {//if the file does not exist, write header
File dataFile = SD.open(DATA_LOG, FILE_WRITE);
if (dataFile) {
dataFile.print("time,temp-dht,humidity-dht,temp-onewire");
for (int i = 1; i <= MYS_MAX_SENSORS; i++) {
dataFile.print(",temp");
dataFile.print(i);
}
for (int i = 1; i <= MYS_MAX_SENSORS; i++) {
dataFile.print(",batt");
dataFile.print(i);
}
dataFile.print("\n");
dataFile.close();
}
}
}
else
{
sd_stat = ERR;
}
}
//reads the last line of the datalog-file to initialize the mysensor-values with the last values after reset.
void readLastMyS() {
File dataFile = SD.open(DATA_LOG, FILE_READ);
char buf[106];
char *str, *p;
if (dataFile) { //11 date 6 time 6 dhttemp 6 dhthum 6 onewire 6*6 onewire 6*4 onewire = 101 max 56 min
unsigned long filesize = dataFile.size();
dataFile.seek(filesize - 106);
dataFile.find("\n");
dataFile.readBytesUntil('\n', buf, 105); //read a line
uint8_t j = 0;
for (str = strtok_r(buf, ",", &p); // goto last entry before MyS-Data
str && j < 3;
str = strtok_r(NULL, ",", &p)
) {
j++;
}
for (int i = 0; i < MYS_MAX_SENSORS; i++) { //read MyS-temps
str = strtok_r(NULL, ",", &p);
if (str) {
tempMyS[i] = atof(str);
}
else break;
}
for (int i = 0; i < MYS_MAX_SENSORS; i++) { //read MyS batts
str = strtok_r(NULL, ",", &p);
if (str) {
battMyS[i] = atoi(str);
}
else break;
}
}
}
void(* reset_func) (void) = 0; //declare reset function @ address 0
void setup() {
pinMode(BUTTON_RIGHT_PIN, INPUT_PULLUP);
pinMode(BUTTON_LEFT_PIN, INPUT_PULLUP);
pinMode(BUTTON_UP_PIN, INPUT_PULLUP);
pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP);
pinMode(BUTTON_ENTER_PIN, INPUT_PULLUP);
LoadParameters(); //load hw-state from eeprom
if (digitalRead(BUTTON_ENTER_PIN) == LOW) nrf_stat = OFF; //to power up without NRF24, hold down enter button on startup (no error state)
//startup hardware
pinMode(ONE_WIRE_GND, OUTPUT);
pinMode(ONE_WIRE_VCC, OUTPUT);
digitalWrite(ONE_WIRE_GND, LOW);
digitalWrite(ONE_WIRE_VCC, HIGH);
delay(10);//let the sensor power up.
if (onewire_stat != OFF)
{
setup_onewire();
}
if (dht_stat != OFF)
{
setup_dht();
}
if (rtc_stat != OFF)
{
setup_rtc();
}
if (nrf_stat != OFF)//no ERR
{
gw.begin(RF24_PA_MAX, RF24_CUST_CHANNEL, RF24_DATARATE, incomingRadio);
}
else
{
Serial.begin(115200);
}
if (sd_stat != OFF) {
setup_sd();
}
if (sd_stat == ON) { //read last MyS-Data from SD-card
readLastMyS();
}
}
void loop() {
if ( (millis() - lastDHTTime > dht.getMinimumSamplingPeriod()) && (dht_stat == ON) ) //read DHT
{
tempDHT = dht.getTemperature();
humDHT = dht.getHumidity();
lastDHTTime = millis();
}
if ( (millis() - lastOnewireTime >= 750) && (onewire_stat == ON) ) //read onewire-sensor
{
tempOnewire = sensors.getTempCByIndex(1);
sensors.requestTemperatures();
lastOnewireTime = millis();
}
t = now();//read time
if (nrf_stat != OFF) {//process radio
gw.processRadioMessage();
}
updateDisplay();
readButtons();
updateState();//change display states depending on buttons
//write SD
if (sd_stat == ON && (minute(t) % WRITE_MINUTE == 0) && (millis() - lastSDWrite >= 120000)) {
writeLogSD();
}
}
//read and debounce the buttons
void readButtons() {
//inverted for internal pullup
boolean tempright = !digitalRead(BUTTON_RIGHT_PIN);
boolean templeft = !digitalRead(BUTTON_LEFT_PIN);
boolean tempup = !digitalRead(BUTTON_UP_PIN);
boolean tempdown = !digitalRead(BUTTON_DOWN_PIN);
boolean tempenter = !digitalRead(BUTTON_ENTER_PIN);
if (right || left || up || down || enter) //any button last pressed
{
debouncetime = millis();
}
if ( (millis() - debouncetime) > DEBOUNCE_DELAY )
{
if (tempright && !lastright) right = tempright;
if (templeft && !lastleft) left = templeft;
if (tempup && !lastup) up = tempup;
if (tempdown && !lastdown) down = tempdown;
if (tempenter && !lastenter) enter = tempenter;
}
else
{
right = 0; //right stays high only for one loop
left = 0;
up = 0;
down = 0;
enter = 0;
}
lastright = tempright;
lastleft = templeft;
lastup = tempup;
lastdown = tempdown;
lastenter = tempenter;
}
//write line to log-file
void writeLogSD() {
File dataFile = SD.open(DATA_LOG, FILE_WRITE);
if (dataFile) {//"time,temp-dht,humidity-dht,temp-onewire,temp1,temp2,temp3,temp4,temp5,temp6"
//dataFile.print((float)(t) / 86400 + 25569,6); //excel timestamp
dataFile.print(day(t) > 9 ? "" : "0");
dataFile.print(day(t));
dataFile.print(".");
dataFile.print(month(t) > 9 ? "" : "0");
dataFile.print(month(t));
dataFile.print(".");
dataFile.print(year(t));
dataFile.print(" ");
dataFile.print(hour(t) > 9 ? "" : "0");
dataFile.print(hour(t));
dataFile.print(":");
dataFile.print(minute(t) > 9 ? "" : "0");
dataFile.print(minute(t));
dataFile.print(",");
dataFile.print(tempDHT, 1);
dataFile.print(",");
dataFile.print(humDHT, 1);
dataFile.print(",");
dataFile.print(tempOnewire, 1);
for (int i = 0; i < MYS_MAX_SENSORS; i++) {
dataFile.print(",");
dataFile.print(tempMyS[i], 1);
}
for (int i = 0; i < MYS_MAX_SENSORS; i++) {
dataFile.print(",");
dataFile.print(battMyS[i]);
}
dataFile.print("\n");
dataFile.close();
lastSDWrite = millis();
}
}
//returns the number of lines of the logfile
unsigned long readSDFileLines() {
unsigned long numLines = 0;
if (sd_stat != ON) return 0;
File dataFile = SD.open(DATA_LOG, FILE_READ);
while (dataFile.find("\n")) { //find number of lines
numLines++;
}
dataFile.close();
return numLines;
}
//read values from sd-card for the diagramm
void readTempFromSD(uint8_t numToRead, unsigned long startRecord) {
char buf[128];
char *str, *p;
if (sd_stat != ON) return;
File dataFile = SD.open(DATA_LOG, FILE_READ);
for (int i = 0; i < startRecord; i++) {
dataFile.find("\n");
}
for (uint8_t i = 0; i < 128; i++) {
dataFile.readBytesUntil('\n', buf, 127); //read a line
uint8_t j = 0;
for (str = strtok_r(buf, ",", &p); // split using comma
str && j < numToRead; // loop while str is not null an max 5 times
str = strtok_r(NULL, ",", &p) // get subsequent tokens
) {
j++;
}
if (str) {
diagram[i] = atof(str);
}
else {
for (; i < 128; i++) {
diagram[i] = -127;
}
break;
}
}
dataFile.close();
}
//print the diagram
void printTempDiagram() {
int maxtemp = (int) ceil(diagram[0]);//start with valid value
int mintemp = (int) floor(diagram[0]);//start with valid value
for (int i = 126; i >= 0; i--)
{
if (diagram[i] > maxtemp)
{
maxtemp = (int) ceil(diagram[i]);
}
if (diagram[i] < mintemp && diagram[i] > -127)
{
mintemp = (int) floor(diagram[i]);
}
}
u8g.setFont(u8g_font_helvB08);
u8g.setPrintPos(0, TOP_PXL + 8);
u8g.print(maxtemp); //scale
u8g.setPrintPos(0, BOT_PXL);
u8g.print(mintemp); //scale
if (diagramScroll) {
u8g.setPrintPos(30, BOT_PXL);
u8g.print("scroll "); //scale
u8g.print(diagramStart);
}
u8g.setPrintPos(20, 8);
if (numDiagram == 1) {
u8g.print("Temp DHT");
}
else if (numDiagram == 2) {
u8g.print("Hum DHT");
}
else if (numDiagram == 3) {
u8g.print("Temp Onewire");
}
else if (numDiagram > 3 && numDiagram <= (3 + MYS_MAX_SENSORS)) {
u8g.print("Temp MyS ");
u8g.print(numDiagram - 3);
}
else if (numDiagram <= (3 + MYS_MAX_SENSORS * 2)) {
u8g.print("Batt MyS ");
u8g.print(numDiagram - 3 - MYS_MAX_SENSORS);
}
for (int i = 0; i < 128; i++) //print array
{
float pxl = (diagram[i] - mintemp) * (BOT_PXL - TOP_PXL) / (-maxtemp + mintemp) + BOT_PXL;
if (diagram[i] >= mintemp && diagram[i] <= maxtemp) //dont print if out of boundery
{
u8g.drawPixel(i, (int)pxl);
}
}
}
//dump the logfile to the serial port
void dumpFile() {
if (sd_stat == ON) {
File dataFile = SD.open(DATA_LOG, FILE_READ);
if (dataFile) {
while (dataFile.available()) {
Serial.write(dataFile.read());
}
dataFile.close();
}
}
}
//updates the state-variables depending on pressed buttons
void updateState() {
switch (dispstat)
{
case PAGE1:
if (right == true) dispstat = PAGE2;
if (left == true) dispstat = HW_SET;
if (enter == true) dumpFile();
break;
case PAGE2:
if (right == true) dispstat = PAGE3;
if (left == true) dispstat = PAGE1;
if (up == true || down == true) dispOnewire = !dispOnewire;
break;
case PAGE3:
if (right == true) dispstat = PAGE4;
if (left == true) dispstat = PAGE2;
if (up == true || down == true) dispOnewire = !dispOnewire;
break;
case PAGE4:
if (right == true) dispstat = PAGE5;
if (left == true) dispstat = PAGE3;
if (up == true || down == true) dispOnewire = !dispOnewire;
break;
case PAGE5:
if (right == true) dispstat = DIAGRAM;
if (left == true) dispstat = PAGE4;
break;
case DIAGRAM:
if (right == true) {
if (diagramScroll == false) {
dispstat = CLOCK;
linesUpdate = false;
}
else {
if (diagramStart < lines - 256 && lines > 128) {
diagramStart += 128;
}
else {
diagramStart = lines > 128 ? lines - 128 : 1;
//Serial.print(diagramStart);
}
diagramRead = false;
}
}
else if (left == true) {
if (diagramScroll == false) {
dispstat = PAGE5;
linesUpdate = false;
}
else
{
if (diagramStart > 128) {
diagramStart -= 128;
}
else {
diagramStart = 1;
}
diagramRead = false;
}
}
else if (enter == true) {
diagramScroll = !diagramScroll;
}
//unsigned long diagramStart = 0;
else if (up == true && numDiagram > 1) {
numDiagram--;
diagramRead = false;
}
else if (down == true && numDiagram < (3 + 2 * MYS_MAX_SENSORS)) {
numDiagram++;
diagramRead = false;
}
else if (!linesUpdate) {
lines = readSDFileLines();
diagramStart = lines - 128;
linesUpdate = true;
}
else if (!diagramRead) {
//readTempFromSD(numDiagram, diagramStart);
readTempFromSD(numDiagram, diagramStart);
diagramRead = true;
}
break;
case CLOCK:
if (clock_set == false && right == true) dispstat = HW_SET;
if (clock_set == false && left == true) dispstat = DIAGRAM;
if (enter == true) clock_set = !clock_set;
if (clock_set == true) {
if (left == true) {
switch (set_digit) {
case SECOND:
set_digit = MINUTE;
break;
case MINUTE:
set_digit = HOUR;
break;
case HOUR:
set_digit = YEAR;
break;
case YEAR:
set_digit = MONTH;
break;
case MONTH:
set_digit = DAY;
break;
case DAY:
set_digit = SECOND;
break;
}
}
else if (right == true) {
switch (set_digit) {
case SECOND:
set_digit = DAY;
break;
case MINUTE:
set_digit = SECOND;
break;
case HOUR:
set_digit = MINUTE;
break;
case YEAR:
set_digit = HOUR;
break;
case MONTH:
set_digit = YEAR;
break;
case DAY:
set_digit = MONTH;
break;
}
}
if (up == true || down == true) {
int inc = up - down;
int d = day(t);
int m = month(t);
int y = year(t);
int h = hour(t);
int mi = minute(t);
int s = second(t);
switch (set_digit) {
case SECOND:
s += inc;
if (s < 0) s = 59;
if (s > 59) s = 0;
break;
case MINUTE:
mi += inc;
if (mi < 0) mi = 59;
if (mi > 59) mi = 0;
break;
case HOUR:
h += inc;
if (h < 0) h = 23;
if (h > 23) h = 0;
break;
case YEAR:
y += inc;
break;
case MONTH:
m += inc;
if (m < 1) m = 12;
if (m > 12) m = 1;
break;
case DAY:
d += inc;
uint8_t maxday = monthDays[m - 1];
if (LEAP_YEAR(y - 1970) && m == 2) maxday = 29;
if (d < 1) d = maxday;
if (d > maxday) d = 1;
break;
}
//set time
tmElements_t tm = {s, mi, h, 0, d, m, y - 1970};
t = makeTime(tm);
if (rtc_stat == ON) {
rtc.set(t); // set the RTC and the system time to the received value
}
setTime(t);
}
}
break;
case HW_SET:
if (right == true) dispstat = PAGE1;
if (left == true) dispstat = CLOCK;
if (up == true) {
switch (hw_page_stat) {
case DHT_22:
hw_page_stat = SD_CARD;
break;
case DS18B22:
hw_page_stat = DHT_22;
break;
case RTC:
hw_page_stat = DS18B22;
break;
case NRF:
hw_page_stat = RTC;
break;
case SD_CARD:
hw_page_stat = NRF;
break;
}
}
if (down == true) {
switch (hw_page_stat) {
case DHT_22:
hw_page_stat = DS18B22;
break;
case DS18B22:
hw_page_stat = RTC;
break;
case RTC:
hw_page_stat = NRF;
break;
case NRF:
hw_page_stat = SD_CARD;
break;
case SD_CARD:
hw_page_stat = DHT_22;
break;
}
}
if (enter == true) {
switch (hw_page_stat) {
case DHT_22:
if (dht_stat == ON) {
dht_stat = OFF;
tempDHT = 0;
humDHT = 0;
}
else {
dht_stat = ON;
setup_dht();
}
break;
case DS18B22:
if (onewire_stat == ON) {
onewire_stat = OFF;
tempOnewire = 0;
}
else {
onewire_stat = ON;
setup_onewire();
}
break;
case RTC://TBD
if (rtc_stat == ON) {
rtc_stat = OFF;
setSyncProvider(NULL);
}
else {
rtc_stat = ON;
setup_rtc();
}
break;
case NRF:
if (nrf_stat == ON) {
nrf_stat = OFF;
SaveParameters();
reset_func();
}
else {
nrf_stat = ON;
SaveParameters();
reset_func();
}
break;
case SD_CARD:
if (sd_stat == ON) {
sd_stat = OFF;
SD.end();
}
else {
sd_stat = ON;
setup_sd();
}
break;
}
SaveParameters();
}
break;
default:
break;
}
}
//updates the display depending on state-variables
void updateDisplay() {
u8g.firstPage();
do {
switch (dispstat)
{
case PAGE1:
u8g.setFont(u8g_font_helvB08);
u8g.setPrintPos(40, 10);
u8g.print(tempDHT, 1);
u8g.print("\xb0 C ");
u8g.print(humDHT, 1);
u8g.print("%");
u8g.setPrintPos(40, 20);
u8g.print(tempOnewire, 1);
u8g.print("\xb0 C");
u8g.setPrintPos(40, 30);
u8g.print(tempMyS[0], 1);
u8g.print("\xb0 C ");
u8g.print(tempMyS[1], 1);
u8g.print("\xb0 C");
u8g.setPrintPos(40, 40);
u8g.print(tempMyS[2], 1);
u8g.print("\xb0 C ");
u8g.print(tempMyS[3], 1);
u8g.print("\xb0 C");
u8g.setPrintPos(0, 60);
u8g.print(day(t) > 9 ? "" : "0");
u8g.print(day(t));
u8g.print(".");
u8g.print(month(t) > 9 ? "" : "0");
u8g.print(month(t));
u8g.print(".");
u8g.print(year(t));
u8g.print(" ");
u8g.print(hour(t) > 9 ? "" : "0");
u8g.print(hour(t));
u8g.print(":");
u8g.print(minute(t) > 9 ? "" : "0");
u8g.print(minute(t));
u8g.print(":");
u8g.print(second(t) > 9 ? "" : "0");
u8g.print(second(t));
u8g.setFont(u8g_font_5x7);
u8g.setPrintPos(0, 10);
u8g.print("DHT:");
u8g.setPrintPos(0, 20);
u8g.print("Dallas:");
u8g.setPrintPos(0, 30);
u8g.print("MyS:");
break;
case PAGE2:
u8g.setFont(u8g_font_helvB18);
u8g.setPrintPos(20, 30);
u8g.print(dispOnewire ? tempOnewire : tempDHT, 1);
u8g.print("\xb0 C");
u8g.setPrintPos(20, 60);
u8g.print(humDHT, 1);
u8g.print("%");
break;
case PAGE3:
u8g.setFont(u8g_font_helvB10);
u8g.setPrintPos(10, 14);
u8g.print(dispOnewire ? tempOnewire : tempDHT, 1);
u8g.print("\xb0 C");
u8g.setPrintPos(74, 14);
u8g.print(humDHT, 1);
u8g.print("%");
u8g.setPrintPos(0, 38);
u8g.setFont(u8g_font_5x7);
u8g.print("1 ");
u8g.setFont(u8g_font_helvB10);
u8g.print(tempMyS[0], 1);
u8g.print("\xb0 C ");
u8g.setPrintPos(64, 38);
u8g.setFont(u8g_font_5x7);
u8g.print("2 ");
u8g.setFont(u8g_font_helvB10);
u8g.print(tempMyS[1], 1);
u8g.print("\xb0 C ");
u8g.setPrintPos(0, 60);
u8g.setFont(u8g_font_5x7);
u8g.print("3 ");
u8g.setFont(u8g_font_helvB10);
u8g.print(tempMyS[2], 1);
u8g.print("\xb0 C ");
u8g.setPrintPos(64, 60);
u8g.setFont(u8g_font_5x7);
u8g.print("4 ");
u8g.setFont(u8g_font_helvB10);
u8g.print(tempMyS[3], 1);
u8g.print("\xb0 C ");
break;
case PAGE4:
u8g.setFont(u8g_font_helvB18);
u8g.setPrintPos(20, 30);
u8g.print(dispOnewire ? tempOnewire : tempDHT, 1);
u8g.print("\xb0 C");
u8g.setPrintPos(20, 60);
u8g.print(tempMyS[0], 1);
u8g.print("\xb0 C");
u8g.setFont(u8g_font_5x7);
u8g.setPrintPos(0, 30);
u8g.print("in");
u8g.setPrintPos(0, 60);
u8g.print("out");
break;
case PAGE5:
for (uint8_t i = 0; i < MYS_MAX_SENSORS; i++)
{
u8g.setFont(u8g_font_helvB08);
u8g.setPrintPos(0, 10 * (i + 1));
u8g.print(i + 1);
u8g.print(":");
u8g.setPrintPos(10, 10 * (i + 1));
u8g.print(tempMyS[i], 1);
u8g.print("\xb0 C");
u8g.setPrintPos(55, 10 * (i + 1));
u8g.print(battMyS[i]);
u8g.print("%");
u8g.setPrintPos(90, 10 * (i + 1));
if (lastReadMyS[i] == 0) u8g.print("nie");
else if (t - lastReadMyS[i] < 60) {
u8g.print(t - lastReadMyS[i]);
u8g.print("s");
}
else if (t - lastReadMyS[i] < 3600) {
u8g.print((t - lastReadMyS[i]) / 60, 1);
u8g.print("min");
}
else {
u8g.print((t - lastReadMyS[i]) / 3600, 1);
u8g.print("h");
}
}
break;
case DIAGRAM:
printTempDiagram();
break;
case CLOCK:
u8g.setFont(u8g_font_helvB08);
u8g.setPrintPos(14, 40);
u8g.print(day(t) > 9 ? "" : "0");
u8g.print(day(t));
u8g.print(".");
u8g.print(month(t) > 9 ? "" : "0");
u8g.print(month(t));
u8g.print(".");
u8g.print(year(t));
u8g.print(" ");
u8g.print(hour(t) > 9 ? "" : "0");
u8g.print(hour(t));
u8g.print(":");
u8g.print(minute(t) > 9 ? "" : "0");
u8g.print(minute(t));
u8g.print(":");
u8g.print(second(t) > 9 ? "" : "0");
u8g.print(second(t));
if (clock_set == true) {
//u8g.setPrintPos(0,50);
//u8g.print("set");
switch (set_digit) {
case DAY:
u8g.drawFrame(12, 30, 15, 12);
break;
case MONTH:
u8g.drawFrame(27, 30, 15, 12);
break;
case YEAR:
u8g.drawFrame(42, 30, 27, 12);
break;
case HOUR:
u8g.drawFrame(69, 30, 15, 12);
break;
case MINUTE:
u8g.drawFrame(84, 30, 15, 12);
break;
case SECOND:
u8g.drawFrame(99, 30, 15, 12);
break;
}
}
break;
case HW_SET:
u8g.setFont(u8g_font_helvB08);
u8g.setPrintPos(10, 10);
u8g.print("DHT");
u8g.setPrintPos(70, 10);
if (dht_stat == OFF) u8g.print("OFF");
if (dht_stat == ON) u8g.print("ON");
if (dht_stat == ERR) u8g.print("ERR");
u8g.setPrintPos(10, 20);
u8g.print("DS18B20");
u8g.setPrintPos(70, 20);
if (onewire_stat == OFF) u8g.print("OFF");
if (onewire_stat == ON) u8g.print("ON");
if (onewire_stat == ERR) u8g.print("ERR");
u8g.setPrintPos(10, 30);
u8g.print("RTC");
u8g.setPrintPos(70, 30);
if (rtc_stat == OFF) u8g.print("OFF");
if (rtc_stat == ON) u8g.print("ON");
if (rtc_stat == ERR) u8g.print("ERR");
u8g.setPrintPos(10, 40);
u8g.print("NRF");
u8g.setPrintPos(70, 40);
if (nrf_stat == OFF) u8g.print("OFF");
if (nrf_stat == ON) u8g.print("ON");
u8g.setPrintPos(10, 50);
u8g.print("SD");
u8g.setPrintPos(70, 50);
if (sd_stat == OFF) u8g.print("OFF");
if (sd_stat == ON) u8g.print("ON");
if (sd_stat == ERR) u8g.print("ERR");
u8g.drawBitmapP(0, 2 + (hw_page_stat) * 10, 1, 8, ARROW);
break;
default:
break;
}
} while ( u8g.nextPage() );
}
//callback-method called every time something arrives on the radio.
void incomingRadio(char *message) {
char *str, *p, *variable;
uint8_t node = 0;
uint8_t sensor = 0;
uint8_t command = 0;
uint8_t ack = 0;
uint8_t type = 0;
uint8_t i = 0;
//log incoming message on SD-card
if (sd_stat == ON) {
File dataFile = SD.open(MYS_LOG, FILE_WRITE);
if (dataFile) {
dataFile.print(day(t) > 9 ? "" : "0");
dataFile.print(day(t));
dataFile.print(".");
dataFile.print(month(t) > 9 ? "" : "0");
dataFile.print(month(t));
dataFile.print(".");
dataFile.print(year(t));
dataFile.print(" ");
dataFile.print(hour(t) > 9 ? "" : "0");
dataFile.print(hour(t));
dataFile.print(":");
dataFile.print(minute(t) > 9 ? "" : "0");
dataFile.print(minute(t));
dataFile.print(":");
dataFile.print(second(t) > 9 ? "" : "0");
dataFile.print(second(t));
dataFile.print(" ");
dataFile.print(message);
dataFile.close();
}
}
//process string
for (str = strtok_r(message, ";", &p); // split using semicolon
str && i < 6; // loop while str is not null an max 5 times
str = strtok_r(NULL, ";", &p) // get subsequent tokens
) {
switch (i) {
case 0: // Radioid (destination)
node = atoi(str);
break;
case 1: // Childid
sensor = atoi(str);
break;
case 2: // Message type
command = atoi(str);
break;
case 3: // Should we request ack from destination?
ack = atoi(str);
break;
case 4: // Data type
type = atoi(str);
break;
case 5: // Variable value
variable = str;
break;
}
i++;
}
if ( (node <= MYS_MAX_SENSORS) && (command == 1) && (type == 0) ) { //if temp-message: write to array
tempMyS[node - 1] = atof(variable);
lastReadMyS[node - 1] = t;
}
if ( (node <= MYS_MAX_SENSORS) && (command == 3) && (type == 0) ) { //battery
battMyS[node - 1] = atoi(variable);
}
}
//load parameters from eeprom (hardware-states)
void LoadParameters() {
dht_stat = (hw_stat_t) EEPROM.read(DHT_EEPROM_ADR);
onewire_stat = (hw_stat_t) EEPROM.read(ONEWIRE_EEPROM_ADR);
rtc_stat = (hw_stat_t) EEPROM.read(RTC_EEPROM_ADR);
nrf_stat = (hw_stat_t) EEPROM.read(NRF_EEPROM_ADR);
sd_stat = (hw_stat_t) EEPROM.read(SD_EEPROM_ADR);
if (dht_stat == 0xff) dht_stat = ON; //after first boot, set state to one
if (onewire_stat == 0xff) onewire_stat = ON;
if (rtc_stat == 0xff) rtc_stat = ON;
if (nrf_stat == 0xff) nrf_stat = ON;
if (sd_stat == 0xff) sd_stat = ON;
}
//save parameters to eeprom (hardware-states)
void SaveParameters() {
if (dht_stat != (hw_stat_t) EEPROM.read(DHT_EEPROM_ADR)) EEPROM.write(DHT_EEPROM_ADR, (uint8_t) dht_stat);
if (onewire_stat != (hw_stat_t) EEPROM.read(ONEWIRE_EEPROM_ADR)) EEPROM.write(ONEWIRE_EEPROM_ADR, (uint8_t) onewire_stat);
if (rtc_stat != (hw_stat_t) EEPROM.read(RTC_EEPROM_ADR)) EEPROM.write(RTC_EEPROM_ADR, (uint8_t) rtc_stat);
if (nrf_stat != (hw_stat_t) EEPROM.read(NRF_EEPROM_ADR)) EEPROM.write(NRF_EEPROM_ADR, (uint8_t) nrf_stat);
if (sd_stat != (hw_stat_t) EEPROM.read(SD_EEPROM_ADR)) EEPROM.write(SD_EEPROM_ADR, (uint8_t) sd_stat);
}
Hope you like it!