123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- #include <LiquidCrystal.h>
- #include <JC_Button.h>
- #include "Boiler.h"
-
- #define HIBERNATE_DELAY 5000
- #define TEMP_TRIGGER 10
- #define LCD_CHAR_SENSOR 1
-
- #define PIN_BTN_MODE 11
- #define PIN_BTN_MINUS 10
- #define PIN_BTN_PLUS 9
- #define PIN_LCD_LED 8
- #define PIN_LCD_RS 7
- #define PIN_LCD_ENABLE 6
- #define PIN_LCD_D0 5
- #define PIN_LCD_D1 4
- #define PIN_LCD_D2 3
- #define PIN_LCD_D3 2
-
- byte g_sensorChar[8] = {
- B00100,
- B01110,
- B01110,
- B01110,
- B01110,
- B11111,
- B11111,
- B01110,
- };
-
- Button g_btnMode(PIN_BTN_MODE);
- Button g_btnMinus(PIN_BTN_MINUS);
- Button g_btnPlus(PIN_BTN_PLUS);
- Button* g_buttons[3] = {&g_btnMode, &g_btnMinus, &g_btnPlus};
- #define BUTTONS_COUNT (sizeof(g_buttons) / sizeof(*g_buttons))
-
- LiquidCrystal g_lcd(PIN_LCD_RS, PIN_LCD_ENABLE, PIN_LCD_D0, PIN_LCD_D1, PIN_LCD_D2, PIN_LCD_D3);
-
- UiStateEnum g_modeSequence[3] = {WaterSetting, HeaterSetting, Lighting};
- #define MODE_SEQUENCE_COUNT (sizeof(g_modeSequence) / sizeof(*g_modeSequence))
-
- GlobalState g_globalState = {
- .appState = {
- .water = {
- .current = 44,
- .setting = 44,
- .isActive = false
- },
- .heater = {
- .current = 44,
- .setting = 44,
- .isActive = false
- }
- },
- .uiState = {
- .state = Lighting,
- .lastOpMs = 0,
- .modeSequenceIndex = MODE_SEQUENCE_COUNT - 1,
- .isUpdateNeeded = true
- }
- };
-
- void printStateLine(char prefix, const BoilerItemState& boilerItemState, bool isModifying, bool isActive, LiquidCrystal lcd)
- {
- char curTmp[5], setTmp[5], tmp[17];
- dtostrf(boilerItemState.current / 2.0f, 2, 1, curTmp);
- dtostrf(boilerItemState.setting / 2.0f, 2, 1, setTmp);
- int count = snprintf(tmp, sizeof(tmp), "%c: %s [%s]%c%c", prefix, curTmp, setTmp, isModifying ? '<' : ' ', isActive ? LCD_CHAR_SENSOR : ' ');
- for (; count < 17; ++count)
- {
- tmp[count] = ' ';
- }
- tmp[count] = 0;
- lcd.print(tmp);
- }
-
- void printState(const GlobalState& globalState, LiquidCrystal lcd)
- {
- Serial.println("Updating display");
-
- lcd.setCursor(0, 0);
- printStateLine('S', globalState.appState.water, globalState.uiState.state == WaterSetting, globalState.appState.water.isActive, lcd);
- lcd.setCursor(0, 1);
- printStateLine('C', globalState.appState.heater, globalState.uiState.state == HeaterSetting, globalState.appState.heater.isActive, lcd);
- }
-
- void setState(GlobalState& boilerState, UiStateEnum state)
- {
- char tmp[50];
- snprintf(tmp, sizeof(tmp), "Changing state %i => %i", g_globalState.uiState.state, state);
- Serial.println(tmp);
-
- if (state == Lighting)
- {
- digitalWrite(PIN_LCD_LED, 1);
- }
- else if (state == Hibernate)
- {
- digitalWrite(PIN_LCD_LED, 0);
- g_globalState.uiState.modeSequenceIndex = MODE_SEQUENCE_COUNT - 1;
- }
- g_globalState.uiState.state = state;
- g_globalState.uiState.isUpdateNeeded = true;
- }
-
- void checkBoilerItem(BoilerItemState& boilerItemState, UiState uiState)
- {
- if (!boilerItemState.isActive && (boilerItemState.current <= boilerItemState.setting - TEMP_TRIGGER))
- {
- boilerItemState.isActive = true;
- uiState.isUpdateNeeded = true;
- }
- else if (boilerItemState.isActive && (boilerItemState.current >= boilerItemState.setting))
- {
- boilerItemState.isActive = false;
- uiState.isUpdateNeeded = true;
- }
- }
-
- void setup()
- {
- for (unsigned i = 0; i < BUTTONS_COUNT; ++i)
- {
- g_buttons[i]->begin();
- }
-
- pinMode(PIN_LCD_LED, OUTPUT);
- digitalWrite(PIN_LCD_LED, 1);
-
- g_lcd.begin(16, 2);
- g_lcd.createChar(LCD_CHAR_SENSOR, g_sensorChar);
-
- Serial.begin(9600);
- }
-
- void loop()
- {
- const auto& currentMs = millis();
-
- for (unsigned i = 0; i < BUTTONS_COUNT; ++i)
- {
- g_buttons[i]->read();
- if (g_buttons[i]->isPressed())
- {
- g_globalState.uiState.lastOpMs = currentMs;
- break;
- }
- }
-
-
- if (g_globalState.uiState.state == Hibernate)
- {
- for (unsigned i = 0; i < BUTTONS_COUNT; ++i)
- {
- if (g_buttons[i]->wasReleased())
- {
- setState(g_globalState, Lighting);
- break;
- }
- }
- }
- else
- {
- if (currentMs - g_globalState.uiState.lastOpMs >= HIBERNATE_DELAY)
- {
- setState(g_globalState, Hibernate);
- }
- else
- {
- if (g_btnMode.wasReleased())
- {
- g_globalState.uiState.modeSequenceIndex = (g_globalState.uiState.modeSequenceIndex + 1) % MODE_SEQUENCE_COUNT;
- setState(g_globalState, g_modeSequence[g_globalState.uiState.modeSequenceIndex]);
- }
- else if (g_btnMinus.wasReleased() || g_btnPlus.wasReleased())
- {
- BoilerItemState* itemState = NULL;
- if (g_globalState.uiState.state == WaterSetting)
- {
- itemState = &g_globalState.appState.water;
- }
- else if (g_globalState.uiState.state == HeaterSetting)
- {
- itemState = &g_globalState.appState.heater;
- }
-
- if (itemState)
- {
- if (g_btnMinus.wasReleased())
- {
- --itemState->setting;
- }
- else if (g_btnPlus.wasReleased())
- {
- ++itemState->setting;
- }
- g_globalState.uiState.isUpdateNeeded = true;
- }
- }
- }
- }
-
- checkBoilerItem(g_globalState.appState.water, g_globalState.uiState);
- checkBoilerItem(g_globalState.appState.heater, g_globalState.uiState);
-
- if (g_globalState.uiState.isUpdateNeeded)
- {
- printState(g_globalState, g_lcd);
- g_globalState.uiState.isUpdateNeeded = false;
- }
- }
|