#include <U8g2lib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <uRTCLib.h>
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); // [full framebuffer, size = 1024 bytes]
// all the arrays below are generated from images using Image Magick
// scroll down to see the actual code
const unsigned char image_dot[] U8X8_PROGMEM = {0x01};
const unsigned char image_slider[] U8X8_PROGMEM = {0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01};
const unsigned char image_slider_dot[] U8X8_PROGMEM = {0x05,0x07,0x05};
const unsigned char image_arrow_up[] U8X8_PROGMEM = {0x04,0x0e,0x1f};
const unsigned char image_arrow_down[] U8X8_PROGMEM = {0x1f,0x0e,0x04};
const unsigned char image_arrow_right[] U8X8_PROGMEM = {0x01,0x03,0x07,0x03,0x01};
// --------------------------- MENU SETUP --------------------------
const byte NUM_ITEMS = 10; // number of items in the list and also the number of screenshots and screenshots with QR codes (other screens)
const byte MAX_ITEM_LENGTH = 14; // maximum characters for the item name
const char menu_items [NUM_ITEMS] [MAX_ITEM_LENGTH] = { // array with menu item names
// |===========| max 13 char lenght
{ "Beep every" },
{ "Low temp." },
{ "High temp." },
{ "Max load" },
{ "UV lamp min." },
{ "Filter alert" },
{ "Filter outag" },
{ "Feeding" },
{ "Reset stats." },
{ "Back" }
};
// note - when changing the order of items above, make sure the other arrays referencing bitmaps
// also have the same order, for example array "bitmap_icons" for icons, and other arrays for screenshots and QR codes
#define ROTARY_CLK_PIN 3 // pin for CLK pin on rotary encoder
#define ROTARY_DT_PIN 4 // pin for DT pin on rotary encoder
#define ROTARY_SW_PIN 5 // pin for SW pin on rotary encoder
OneWire oneWire(9);
DallasTemperature sensor(&oneWire);
uRTCLib rtc(0x68);
byte item_selected = 2; // which item in the menu is selected
byte button_select_clicked = 0; // same as above
byte current_screen = 10;
/* 0 = main page
1 = power distribution page
2 = usage statistics page
10 = menu - show values
11 = menu - set values
// ----- settings ------
/* 1 = value 00.0 -> 99.0W
2 = value 00.0 -> 99.0°C
6 = values 0-4: OFF / 1 / 3 / 12 / 24h
7 = values 0-4: OFF / 5m / 1h / 12h / 24h
10 = reset stats: 0-1: OK? / CONF.
13 = back to main page
*/
const byte SETTINGS_TYPE [NUM_ITEMS] {
7, // Beep every
2, // Low temp
2, // High temp
1, // Max load
1, // UV lamp min
1, // Filter alert
6, // Filter off delay
1, // Feeding
10, // Reset stats
13 // Back
};
const byte SETTINGS_MIN [NUM_ITEMS] {
0, // Beep every
179, // Low temp
249, // High temp
10, // Max load
0, // UV lamp min
0, // Filter alert
0, // Filter off delay
1, // Feeding
0, // Reset stats
0 // Back
};
const int SETTINGS_MAX [NUM_ITEMS] {
4, // Beep every
250, // Low temp
350, // High temp
999, // Max load
200, // UV lamp min
100, // Filter alert
4, // Filter off delay
100, // Feeding
1, // Reset stats
0 // Back
};
int settings [NUM_ITEMS] { //default values
1, // Beep every
179, // Low temp
280, // High temp
550, // Max load
10, // UV lamp min
20, // Filter alert
0, // Filter off delay
40, // Feeding
0, // Reset stats
0 // Back
};
void setup() {
//Serial.begin(115200);
u8g2.setColorIndex(1); // set the color to white
u8g2.begin();
u8g2.setBitmapMode(1);
delay(100);
sensor.begin();
delay(200);
URTCLIB_WIRE.begin();
// define pins for buttons
// INPUT_PULLUP means the button is HIGH when not pressed, and LOW when pressed
// since it´s connected between some pin and GND
pinMode(ROTARY_CLK_PIN, INPUT);
pinMode(ROTARY_DT_PIN, INPUT);
pinMode(ROTARY_SW_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ROTARY_CLK_PIN), handleEncoder, FALLING);
}
void handleEncoder() {
int dtValue = digitalRead(ROTARY_DT_PIN);
if (dtValue == HIGH) {
if (current_screen == 10) {
if (item_selected == 0) { // if first item was selected, jump to last item
item_selected = NUM_ITEMS - 1;
} else {
item_selected = item_selected - 1; // select previous item
}
}
if (current_screen == 11) {
if (SETTINGS_TYPE[item_selected] < 11 && settings[item_selected] < SETTINGS_MAX[item_selected]) {
settings[item_selected] = settings[item_selected] + 1;
}
}
}
if (dtValue == LOW) {
if (current_screen == 10) {
item_selected = item_selected + 1; // select next item
if (item_selected >= NUM_ITEMS) { // last item was selected, jump to first menu item
item_selected = 0;
}
}
if (current_screen == 11) {
if (SETTINGS_TYPE[item_selected] < 11 && settings[item_selected] > SETTINGS_MIN[item_selected]) {
settings[item_selected] = settings[item_selected] - 1;
}
}
}
}
void convertIntToCharArray(int number, char* output) {
// Extracting individual digits
int digit1 = number / 100;
int digit2 = (number / 10) % 10;
int digit3 = number % 10;
// Constructing the text with comma
if (number > 99) { output[0] = digit1 + '0'; } else {output[0] = ' ';}
output[1] = digit2 + '0';
output[2] = '.';
output[3] = digit3 + '0';
output[4] = '\0'; // Null-terminate the string
}
void loop() {
byte item_sel_previous; // previous item - used in the menu screen to draw the item before the selected one
byte item_sel_next; // next item - used in the menu screen to draw next item after the selected one
if ((digitalRead(ROTARY_SW_PIN) == LOW) && (button_select_clicked == 0)) { // select button clicked, jump between screens
button_select_clicked = 1; // set button to clicked to only perform the action once
if (current_screen == 10) {
current_screen = 11; // menu items screen --> screenshots screen
}
else if (current_screen == 11) {
current_screen = 10; // screenshots screen --> qr codes screen
}
}
if ((digitalRead(ROTARY_SW_PIN) == HIGH) && (button_select_clicked == 1)) { // unclick
button_select_clicked = 0;
}
// set correct values for the previous and next items
if (item_selected == 0) {item_sel_previous = NUM_ITEMS - 1;} // previous item would be below first = make it the last
else { item_sel_previous = item_selected - 1;}
item_sel_next = item_selected + 1;
if (item_sel_next >= NUM_ITEMS) {
item_sel_next = 0; // next item would be after last = make it the first
}
u8g2.clearBuffer(); // clear buffer for storing display content in RAM
// ---- temp read
sensor.requestTemperatures();
float temp = sensor.getTempCByIndex(0);
char tmp[4];
itoa(temp*100,tmp,10);
/*
u8g2.setDrawColor(1);
u8g2.setFont(u8g2_font_6x13_tr);
u8g2.drawStr(3, 15, "Temperature:");
u8g2.drawStr(3, 30, tmp);
*/
// ----- time read
rtc.refresh();
char sec[2];
itoa(rtc.second(),sec,10);
//u8g2.setDrawColor(1);
//u8g2.setFont(u8g2_font_6x13_tr);
//u8g2.drawStr(3, 30, sec);
// ----- amp read
int sensorAmp1raw = analogRead(A0);
int sensorAmp2raw = analogRead(A1);
int sensorAmp3raw = analogRead(A2);
int sensorAmp4raw = analogRead(A3);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
// float amp1 = sensorAmp1raw * (5.0 / 1023.0);
char amp1[5];
char amp2[5];
char amp3[5];
char amp4[5];
itoa(sensorAmp1raw,amp1,10);
itoa(sensorAmp2raw,amp2,10);
itoa(sensorAmp3raw,amp3,10);
itoa(sensorAmp4raw,amp4,10);
/*
u8g2.setDrawColor(1);
u8g2.setFont(u8g2_font_6x13_tr);
u8g2.drawStr(3, 15, amp1);
u8g2.drawStr(3, 30, amp2);
u8g2.drawStr(3, 45, amp3);
u8g2.drawStr(3, 60, amp4);
*/
if (current_screen == 10 || current_screen == 11) { // MENU SCREEN: normal || selected item
// footer
u8g2.setFontMode(1);
u8g2.setBitmapMode(1);
u8g2.drawBox(0, 0, 128, 11);
u8g2.setDrawColor(2);
u8g2.setFont(u8g2_font_4x6_tr);
u8g2.drawStr(3, 8, "Menu > ");
// memory saving
if (item_selected < 8) {u8g2.drawStr(31, 8, "Alert setup");}
else if (item_selected == 8) {u8g2.drawStr(31, 8, "Indicators");}
// selector frame
u8g2.setDrawColor(2);
if (current_screen == 11) {
u8g2.drawBox(0, 30, 123, 17);
u8g2.drawXBMP(102, 50, 5, 3, image_arrow_down);
u8g2.drawXBMP(102, 25, 5, 3, image_arrow_up);
}
else
{
u8g2.drawFrame(0, 30, 123, 17);
u8g2.drawXBMP(84, 36, 3, 5, image_arrow_right);
}
u8g2.drawXBMP(0, 30, 1, 1, image_dot);
u8g2.drawXBMP(122, 30, 1, 1, image_dot);
u8g2.drawXBMP(0, 46, 1, 1, image_dot);
u8g2.drawLine(2, 47, 121, 47);
u8g2.drawLine(123, 32, 123, 45);
// first line caption
u8g2.setDrawColor(1);
u8g2.setFont(u8g2_font_6x13_tr);
u8g2.drawStr(5, 26, menu_items[item_sel_previous]);
// second line caption
u8g2.setDrawColor(2);
u8g2.setFont(u8g2_font_6x13B_tr);
u8g2.drawStr(5, 43, menu_items[item_selected]);
// second line value
/* 1 = value 00.0 -> 99.0W
2 = value 00.0 -> 99.0°C
6 = values 0-4: OFF / 1 / 3 / 12 / 24h
7 = values 0-4: OFF / 5m / 1h / 12h / 24h
10 = reset stats: 0-1: OK? / DONE
11 = open stat page
12 = open power distr page
13 = open main page
*/
u8g2.setDrawColor(2);
u8g2.setFont(u8g2_font_6x12_tr);
if (SETTINGS_TYPE[item_selected] == 1 || SETTINGS_TYPE[item_selected] == 2) {
char settingsVal[5];
if (settings[item_selected] == SETTINGS_MIN[item_selected]) {
u8g2.drawStr(89, 42, " OFF");
} else {
convertIntToCharArray(settings[item_selected], settingsVal);
u8g2.drawStr(89, 42, settingsVal);
u8g2.setFont(u8g2_font_6x13_tr);
if (SETTINGS_TYPE[item_selected] == 1) {
u8g2.drawStr(114, 42, "w");
} else {
u8g2.drawStr(114, 42, "c");
}
}
} else if (SETTINGS_TYPE[item_selected] == 6) {
if (settings[item_selected] == 0) { u8g2.drawStr(89, 42, " OFF"); }
else if (settings[item_selected] == 1) { u8g2.drawStr(89, 42, " 1h"); }
else if (settings[item_selected] == 2) { u8g2.drawStr(89, 42, " 3h"); }
else if (settings[item_selected] == 3) { u8g2.drawStr(89, 42, " 12h"); }
else if (settings[item_selected] == 4) { u8g2.drawStr(89, 42, " 24h"); }
} else if (SETTINGS_TYPE[item_selected] == 7) {
if (settings[item_selected] == 0) { u8g2.drawStr(89, 42, " OFF"); }
else if (settings[item_selected] == 1) { u8g2.drawStr(89, 42, " 5m"); }
else if (settings[item_selected] == 2) { u8g2.drawStr(89, 42, " 1h"); }
else if (settings[item_selected] == 3) { u8g2.drawStr(89, 42, " 12h"); }
else if (settings[item_selected] == 4) { u8g2.drawStr(89, 42, " 24h"); }
} else if (SETTINGS_TYPE[item_selected] == 10) {
if (settings[item_selected] == 0) { u8g2.drawStr(89, 42, " OK?"); }
else if (settings[item_selected] == 1) { u8g2.drawStr(89, 42, " DONE"); }
} else {
u8g2.drawStr(89, 42, " OPEN");
}
// third line cation
u8g2.setDrawColor(1);
u8g2.setFont(u8g2_font_6x13_tr);
u8g2.drawStr(5, 61, menu_items[item_sel_next]);
// slider handling
u8g2.drawXBMP(126, 12, 1, 51, image_slider);
u8g2.drawBox(125, 12 + ((64 - 12) / NUM_ITEMS * item_selected), 3, 64 / NUM_ITEMS); // +2 is manual correction
}
u8g2.sendBuffer(); // send buffer from RAM to display controller
//delay(1000);
} Laskakit -- module 1 -- module 2 -- module 3