Mobile weather station at Arduino
Probably everyone who begins his acquaintance with the Arduino, blinking the LED and connecting a button, proceeds to create his own meteorological station. I am no exception.
After reviewing various projects on the Internet, certain requirements were made. The device should display the time, temperature, pressure and schedule of its change. I also wanted to calculate the phases of the moon and the time of sunrise and sunset. And the most important requirement was mobility. The portable weather station being created was supposed to be used as an aid for fishing, so it had to be compact in size and have a certain autonomy.
Creating a case for any homemade is quite a challenge. A Motorola T192 mobile phone was found in the bins.

It turned out that the screen from Nokia 3310 becomes excellent in it (of course, it would be more convenient to use the Nokia 3310 itself).
Manage everything was assigned to the Arduino Pro Mini.

In order not to fail the buttons, a breadboard was inserted. When glueing the keyboard, it was noticed that the pitch of the holes of the breadboard almost coincided with the buttons. In the future, this allowed the use of buttons.

To measure the pressure applied sensor bmp180. The ds1302 module was taken as a clock, but to save space, only a microcircuit was taken from it. Quartz was dropped from the motherboard, and the battery was removed from the laptop (of course, you can also use the regular cr2032 in a thermocommetric).

Since there were free exits, the display backlight was hung on one of the free and the button on the second.

A Li-ion charge module on the TP4056 was used to charge the lithium battery.

The final view of the device (the wires sticking out on the right are for firmware, so they will soon be removed.)

When writing the program, the usual means were used. The only thing I would like to draw attention to the library TimeLord.h (https://github.com/probonopd/TimeLord). With the help of its functions, specifying the date, coordinates and time zone, you can determine the time of sunrise and sunset, the phase of the moon. Description can be downloaded at the link: TimeLord.pdf .
With regards to battery life, a short test showed that the device will work for a week exactly. This result is quite satisfactory, so further experiments on energy saving have been postponed.
The sketch currently uses 81% of the device's memory, so it is possible to add something else.

An antenna is displayed on the screen (signal strength indicator). This is a reserve for testing the radio module at 433 MHz, for obtaining the true temperature and humidity from an external module.
After reviewing various projects on the Internet, certain requirements were made. The device should display the time, temperature, pressure and schedule of its change. I also wanted to calculate the phases of the moon and the time of sunrise and sunset. And the most important requirement was mobility. The portable weather station being created was supposed to be used as an aid for fishing, so it had to be compact in size and have a certain autonomy.
Creating a case for any homemade is quite a challenge. A Motorola T192 mobile phone was found in the bins.

It turned out that the screen from Nokia 3310 becomes excellent in it (of course, it would be more convenient to use the Nokia 3310 itself).
Manage everything was assigned to the Arduino Pro Mini.

In order not to fail the buttons, a breadboard was inserted. When glueing the keyboard, it was noticed that the pitch of the holes of the breadboard almost coincided with the buttons. In the future, this allowed the use of buttons.

To measure the pressure applied sensor bmp180. The ds1302 module was taken as a clock, but to save space, only a microcircuit was taken from it. Quartz was dropped from the motherboard, and the battery was removed from the laptop (of course, you can also use the regular cr2032 in a thermocommetric).

Since there were free exits, the display backlight was hung on one of the free and the button on the second.

A Li-ion charge module on the TP4056 was used to charge the lithium battery.

The final view of the device (the wires sticking out on the right are for firmware, so they will soon be removed.)

When writing the program, the usual means were used. The only thing I would like to draw attention to the library TimeLord.h (https://github.com/probonopd/TimeLord). With the help of its functions, specifying the date, coordinates and time zone, you can determine the time of sunrise and sunset, the phase of the moon. Description can be downloaded at the link: TimeLord.pdf .
With regards to battery life, a short test showed that the device will work for a week exactly. This result is quite satisfactory, so further experiments on energy saving have been postponed.
The sketch currently uses 81% of the device's memory, so it is possible to add something else.

An antenna is displayed on the screen (signal strength indicator). This is a reserve for testing the radio module at 433 MHz, for obtaining the true temperature and humidity from an external module.
Source code
#include<BMP085.h>#include<EEPROM.h>#include<Adafruit_GFX.h>#include<Adafruit_PCD8544.h>#include<DS1302.h>#include<TimeLord.h>#include<Wire.h>//84x48
Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 6, 7);
// Create a DS1302 object.DS1302 rtc(12, 11, 10);// Chip Enable, Input/Output, Serial Clock
Time t = rtc.time();
String dayAsString(const Time::Day day){
switch (day) {
case Time::kSunday: return"Sunday";
case Time::kMonday: return"Monday";
case Time::kTuesday: return"Tuesday";
case Time::kWednesday: return"Wednesday";
case Time::kThursday: return"Thursday";
case Time::kFriday: return"Friday";
case Time::kSaturday: return"Saturday";
}
return"(unknown day)";
}
//-------------
TimeLord tardis;
floatconst LATITUDE = 52.70;
floatconst LONGITUDE = 25.40;
//byte today[] = {0,0,12,22,03,16};
byte today[6];
//-------------//long previousMillis = 0, previousMillis2 = 0; // храним время последней команды//long interval = 1800000; // интервал между командами//long interval = 3600000; // интервал между командами//long interval2 = 1000; // интервал между командами
byte prevSecond = 99, prevHour = 99;
//-------------
BMP085 dps = BMP085();
long Temperature = 0, Pressure = 0;
float t_f = 0;
//-------------buttons--------------------int buttonPushCounter = 0;
int buttonState = 0;
int lastButtonState = 0;
//-------------moon----------------------//0.0 New Moon 0.99 - Almost newconstunsignedchar PROGMEM moon0[] =
{ B00000111, B11100000,
B00001000, B00010000,
B00010000, B00001000,
B00100000, B00000100,
B01000000, B00000010,
B10000000, B00000001,
B10000000, B00000001,
B10000000, B00000001,
B10000000, B00000001,
B10000000, B00000001,
B01000000, B00000010,
B00100000, B00000100,
B00010000, B00001000,
B00001000, B00010000,
B00000111, B11100000
};
//Waxing Crescentconstunsignedchar PROGMEM moon1[] =
{ B00000111, B11100000,
B00001000, B01110000,
B00010000, B00111000,
B00100000, B00011100,
B01000000, B00001110,
B10000000, B00001111,
B10000000, B00001111,
B10000000, B00001111,
B10000000, B00001111,
B10000000, B00001111,
B01000000, B00001110,
B00100000, B00011100,
B00010000, B00111000,
B00001000, B01110000,
B00000111, B11100000
};
//0.25 First Quarterconstunsignedchar PROGMEM moon2[] =
{ B00000111, B11100000,
B00001000, B11110000,
B00010000, B11111000,
B00100000, B11111100,
B01000000, B11111110,
B10000000, B11111111,
B10000000, B11111111,
B10000000, B11111111,
B10000000, B11111111,
B10000000, B11111111,
B01000000, B11111110,
B00100000, B11111100,
B00010000, B11111000,
B00001000, B11110000,
B00000111, B11100000
};
//Waxing Gibbousconstunsignedchar PROGMEM moon3[] =
{ B00000111, B11100000,
B00001011, B11110000,
B00010111, B11111000,
B00101111, B11111100,
B01001111, B11111110,
B10001111, B11111111,
B10001111, B11111111,
B10001111, B11111111,
B10001111, B11111111,
B10001111, B11111111,
B01001111, B11111110,
B00101111, B11111100,
B00010111, B11111000,
B00001011, B11110000,
B00000111, B11100000
};
//0.5 Full Moonconstunsignedchar PROGMEM moon4[] =
{ B00000111, B11100000,
B00001111, B11110000,
B00011111, B11111000,
B00111111, B11111100,
B01111111, B11111110,
B11111111, B11111111,
B11111111, B11111111,
B11111111, B11111111,
B11111111, B11111111,
B11111111, B11111111,
B01111111, B11111110,
B00111111, B11111100,
B00011111, B11111000,
B00001111, B11110000,
B00000111, B11100000
};
//Waning Gibbousconstunsignedchar PROGMEM moon5[] =
{ B00000111, B11100000,
B00001111, B11010000,
B00011111, B11101000,
B00111111, B11110100,
B01111111, B11110010,
B11111111, B11110001,
B11111111, B11110001,
B11111111, B11110001,
B11111111, B11110001,
B11111111, B11110001,
B01111111, B11110010,
B00111111, B11110100,
B00011111, B11101000,
B00001111, B11010000,
B00000111, B11100000
};
//0.75 Third Quarter (Last Quarter)constunsignedchar PROGMEM moon6[] =
{ B00000111, B11100000,
B00001111, B00010000,
B00011111, B00001000,
B00111111, B00000100,
B01111111, B00000010,
B11111111, B00000001,
B11111111, B00000001,
B11111111, B00000001,
B11111111, B00000001,
B11111111, B00000001,
B01111111, B00000010,
B00111111, B00000100,
B00011111, B00001000,
B00001111, B00010000,
B00000111, B11100000
};
//Waning Crescentconstunsignedchar PROGMEM moon7[] =
{ B00000111, B11100000,
B00001110, B00010000,
B00011100, B00001000,
B00111000, B00000100,
B01110000, B00000010,
B11110000, B00000001,
B11110000, B00000001,
B11110000, B00000001,
B11110000, B00000001,
B11110000, B00000001,
B01110000, B00000010,
B00111000, B00000100,
B00011100, B00001000,
B00001110, B00010000,
B00000111, B11100000
};
//=====================================================================================voiddrawMoon(int moon_x, int moon_y, int phase){
display.fillRect(moon_x, moon_y, 16, 15, WHITE);
display.drawBitmap(moon_x, moon_y, moon4, 16, 15, WHITE);
switch (phase) {
case0:
display.drawBitmap(moon_x, moon_y, moon0, 16, 15, BLACK);
break;
case1:
display.drawBitmap(moon_x, moon_y, moon1, 16, 15, BLACK);
break;
case2:
display.drawBitmap(moon_x, moon_y, moon2, 16, 15, BLACK);
break;
case3:
display.drawBitmap(moon_x, moon_y, moon3, 16, 15, BLACK);
break;
case4:
display.drawBitmap(moon_x, moon_y, moon4, 16, 15, BLACK);
break;
case5:
display.drawBitmap(moon_x, moon_y, moon5, 16, 15, BLACK);
break;
case6:
display.drawBitmap(moon_x, moon_y, moon6, 16, 15, BLACK);
break;
case7:
display.drawBitmap(moon_x, moon_y, moon7, 16, 15, BLACK);
break;
default:
display.drawBitmap(moon_x, moon_y, moon4, 16, 15, WHITE);
}
}
//===========================================================================================voiddrawMoonDate(int moon_x, int moon_y, uint8_t * datetoday){
float phase;
phase = tardis.MoonPhase(datetoday);
if (phase >= 0.0 && phase <= 0.0625) {
drawMoon(moon_x, moon_y, 0);
}; //0.000 New moonif (phase > 0.0625 && phase <= 0.1875) {
drawMoon(moon_x, moon_y, 1);
}; //0,125if (phase > 0.1875 && phase <= 0.3125 ) {
drawMoon(moon_x, moon_y, 2);
}; //0.250 First Quarterif (phase > 0.3125 && phase <= 0.4375) {
drawMoon(moon_x, moon_y, 3);
}; //0,375if (phase > 0.4375 && phase <= 0.5625) {
drawMoon(moon_x, moon_y, 4);
}; //0.500 Fullif (phase > 0.5625 && phase <= 0.6875) {
drawMoon(moon_x, moon_y, 5);
}; //0,625if (phase > 0.6875 && phase <= 0.8125) {
drawMoon(moon_x, moon_y, 6);
}; //0.750 Last Quarterif (phase > 0.8125 && phase <= 0.9375) {
drawMoon(moon_x, moon_y, 7);
}; //0.875if (phase > 0.9375 && phase <= 1) {
drawMoon(moon_x, moon_y, 0);
}; //0.990 Almost new
}
//=====================================================================================voiddrawSignal(float streng){
display.fillRect(0, 0, 12, 6, WHITE);
display.drawTriangle(0, 0, 8, 0, 4, 4, BLACK);
display.drawLine(4, 0, 4, 6, BLACK);
display.drawLine(6, 5, 6, 6, BLACK);
display.drawLine(8, 4, 8, 6, BLACK);
display.drawLine(10, 2, 10, 6, BLACK);
display.drawLine(12, 0, 12, 6, BLACK);
}
//=====================================================================================voiddrawBatteryState(float v_bat){
display.fillRect(68, 0, 16, 7, WHITE);
display.drawRect(83, 2, 1, 3, BLACK);
display.drawRoundRect(68, 0, 15, 7, 2, BLACK);
// 3, 44 4, 2 0, 76 0, 152//4,200 full 4//4,048 3//3,896 2//3,744 1//3,592 0//3,440 zero -if (v_bat > 4500) {
display.fillRect(70, 2, 10, 3, BLACK);
}
if (v_bat > 4048) {
display.drawRect(79, 2, 2, 3, BLACK);
}
if (v_bat > 3896) {
display.drawRect(76, 2, 2, 3, BLACK);
}
if (v_bat > 3744) {
display.drawRect(73, 2, 2, 3, BLACK);
}
if (v_bat > 3592) {
display.drawRect(70, 2, 2, 3, BLACK);
}
}
//=====================================================================================voiddrawTime(byte x, byte y){
display.fillRect(0 + x, 0 + y, 48, 7, WHITE);
//display.fillRect(0+x, 0+y, 30, 7, WHITE);
Time t = rtc.time();
display.setTextColor(BLACK);
display.setTextSize(1);
display.setCursor(x, y);
display.print(t.hr);
display.print(":");
display.print(t.min);
display.print(":");
display.print(t.sec);
}
//===========================================================================================voidupdateMoonSunDate(){
Time t = rtc.time();
today[0] = 0;
today[1] = 0;
today[2] = 12;
today[3] = t.date;
today[4] = t.mon;
today[5] = t.yr - 2000;
}
//=====================================================================================voiddrawSunRiseSet(byte x, byte y){
updateMoonSunDate();
display.setTextSize(1);
display.setTextColor(BLACK);
display.fillRect(x, y, 33, y + 8, WHITE);
if (tardis.SunRise(today)) // if the sun will rise today (it might not, in the [ant]arctic)
{
display.setCursor(x, y);
display.print((int) today[tl_hour]);
display.print(":");
display.println((int) today[tl_minute]);
}
if (tardis.SunSet(today)) // if the sun will set today (it might not, in the [ant]arctic)
{
display.setCursor(x, y + 8);
display.print((int) today[tl_hour]);
display.print(":");
display.println((int) today[tl_minute]);
}
}
//=====================================================================================voiddrawPressure(byte x, byte y){
display.setTextSize(1);
display.setTextColor(BLACK);
display.fillRect(x, y, 33, y + 8, WHITE);
display.setCursor(x, y);
t_f = Temperature;
display.println( t_f / 10, 1);
display.setCursor(x, y + 8);
//display.println(ceil(Pressure / 133.3), 0);
display.println(Pressure / 133.3, 1);
}
//=====================================================================================longreadVcc(){
// Read 1.1V reference against AVcc// set the reference to Vcc and the measurement to the internal 1.1V reference#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delay(75); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Start conversionwhile (bit_is_set(ADCSRA, ADSC)); // measuringuint8_t low = ADCL; // must read ADCL first - it then locks ADCHuint8_t high = ADCH; // unlocks bothlong result = (high << 8) | low;
//scale_constant = internal1.1Ref * 1023 * 1000//где//internal1.1Ref = 1.1 * Vcc1 (показания_вольтметра) / Vcc2 (показания_функции_readVcc())//4.967/4600-------1215079.369565217// result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*100000
result = 1132060 / result;
return result; // Vcc in millivolts//http://blog.unlimite.net/?p=25
}
//===========================================================================================voiddrawVcc(byte x, byte y, word vcc){
display.setTextSize(1);
display.setTextColor(BLACK);
display.fillRect(x, y, 33, y + 8, WHITE);
display.setCursor(x, y);
display.println(vcc);
}
//=====================================================================================voidpressure_drawLine(byte x, byte h){
display.drawLine(x, 47 - h, x, 47, BLACK);
}
voidpressure_drawGraph(){
display.fillRect(0, 25, 83, 47, WHITE);
for (int i = 0; i <= 83; i++) {
pressure_drawLine(i, EEPROM.read(i));
}
}
//===========================================================================================voidsetup(){
Serial.begin(9600);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(2, OUTPUT);
//-----------------------------------------------------------------------------//rtc.writeProtect(false);//rtc.halt(false);
String day = dayAsString(t.day);
//-----------------------------------------------------------------------------
tardis.TimeZone(3 * 55);
tardis.Position(LATITUDE, LONGITUDE);
//-----------------------------------------------------------------------------
Wire.begin();
display.begin();
display.setContrast(55);
display.clearDisplay();
display.drawLine(0, display.height() / 2, display.width(), display.height() / 2, BLACK);
dps.init();
updateMoonSunDate();
drawMoonDate(34, 8, today);
pressure_drawGraph();
display.display();
prevHour = rtc.time().hr;
//EEPROM.write(0, 9);// for (int i=0; i <= 83; i++){// EEPROM.write(i, random(1, 23));// pressure_drawLine(i,EEPROM.read(i));// Serial.println(EEPROM.read(i));// }
}
//=====================================================================================voidloop(){
unsignedlong currentMillis = millis();
unsignedlong currentMillis2 = millis();
byte temp;
//timer---------------------- 1 hour// if (currentMillis - previousMillis > interval) {// previousMillis = currentMillis;if (rtc.time().hr != prevHour) {
prevHour = rtc.time().hr;
dps.getPressure(&Pressure);
dps.getTemperature(&Temperature);
for (int i = 0; i <= 82; i++) {
temp = EEPROM.read(i + 1);
EEPROM.write(i, temp);
}
EEPROM.write(83, ceil(Pressure / 133.3) - 740);
pressure_drawGraph();
display.display();
}
//timer---------------------- 1 sec// if (currentMillis2 - previousMillis2 > interval2) {// previousMillis2 = currentMillis2;if (rtc.time().sec != prevSecond) {
prevSecond = rtc.time().sec;
dps.getPressure(&Pressure);
dps.getTemperature(&Temperature);
updateMoonSunDate();
drawPressure(0, 8);
drawTime(17, 0);
drawSunRiseSet(53, 8);
drawMoonDate(34, 8, today);
drawBatteryState(readVcc());
drawSignal(5);
// drawVcc(0, 16, readVcc());
display.display();
}
//timer----------------------
buttonState = digitalRead(8);
// Serial.println(buttonState);if (buttonState != lastButtonState) {
if (buttonState == HIGH) {
buttonPushCounter++;
}
}
lastButtonState = buttonState;
if (buttonPushCounter % 2 == 0) {
digitalWrite(2, HIGH);
} else {
digitalWrite(2, LOW);
}
}
//=====================================================================================