2018-12-01 00:36:25 +00:00
|
|
|
#include <Arduino.h>
|
|
|
|
#include "ScreenHeader.h"
|
|
|
|
#include "Protocol.h"
|
|
|
|
#include "128x64OLED.h"
|
|
|
|
#include "BTCWifi.h"
|
|
|
|
#include "BluetoothAbstract.h"
|
2018-12-01 18:25:10 +00:00
|
|
|
#include "Icons.h"
|
2018-12-01 00:36:25 +00:00
|
|
|
#include "MiniFont.h"
|
|
|
|
#include "helpers.h"
|
2018-12-07 11:16:04 +00:00
|
|
|
#include "NVStorage.h"
|
2018-12-08 22:51:16 +00:00
|
|
|
#include "Clock.h"
|
2018-12-07 11:16:04 +00:00
|
|
|
#include "Arial.h"
|
|
|
|
|
2018-12-01 00:36:25 +00:00
|
|
|
|
|
|
|
#define MINIFONT miniFontInfo
|
|
|
|
|
2018-12-07 11:16:04 +00:00
|
|
|
#define X_BATT_ICON 103
|
2018-12-01 00:36:25 +00:00
|
|
|
#define Y_BATT_ICON 0
|
2018-12-07 11:16:04 +00:00
|
|
|
#define X_WIFI_ICON 19
|
2018-12-01 00:36:25 +00:00
|
|
|
#define Y_WIFI_ICON 0
|
2018-12-07 11:16:04 +00:00
|
|
|
#define X_BT_ICON 10
|
2018-12-01 00:36:25 +00:00
|
|
|
#define Y_BT_ICON 0
|
2018-12-07 11:16:04 +00:00
|
|
|
#define X_TIMER1_ICON 69
|
|
|
|
#define X_TIMER2_ICON 85
|
|
|
|
#define Y_TIMER_ICON 0
|
|
|
|
#define X_CLOCK 52
|
|
|
|
#define Y_CLOCK 0
|
|
|
|
|
2018-12-01 00:36:25 +00:00
|
|
|
|
|
|
|
CScreenHeader::CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr) : CScreen(disp, mgr)
|
|
|
|
{
|
2018-12-01 19:14:34 +00:00
|
|
|
_clearUpAnimation = false;
|
|
|
|
_clearDnAnimation = false;
|
2018-12-01 00:36:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CScreenHeader::show()
|
|
|
|
{
|
|
|
|
_display.clearDisplay();
|
|
|
|
|
|
|
|
// standard header items
|
2018-12-01 18:51:53 +00:00
|
|
|
// Bluetooth
|
2018-12-02 06:30:40 +00:00
|
|
|
showBTicon();
|
|
|
|
|
2018-12-01 00:36:25 +00:00
|
|
|
// WiFi
|
2018-12-02 06:30:40 +00:00
|
|
|
showWifiIcon();
|
|
|
|
|
2018-12-01 00:36:25 +00:00
|
|
|
// battery
|
|
|
|
showBatteryIcon(getHeaterInfo().getBattVoltage());
|
|
|
|
|
2018-12-07 11:16:04 +00:00
|
|
|
// timers
|
|
|
|
int numTimers = showTimers();
|
|
|
|
|
2018-12-02 06:30:40 +00:00
|
|
|
// clock
|
2018-12-07 11:16:04 +00:00
|
|
|
showTime(numTimers);
|
2018-12-01 00:36:25 +00:00
|
|
|
}
|
|
|
|
|
2018-12-01 18:51:53 +00:00
|
|
|
// Animate IN/OUT arrows against the WiFi icon, according to actual web server traffic:
|
|
|
|
// an IN (down) arrow is drawn if incoming data has been detected.
|
|
|
|
// an OUT (up) arrow is drawn if outgoing data has been sent.
|
2018-12-01 18:25:10 +00:00
|
|
|
//
|
2018-12-01 18:51:53 +00:00
|
|
|
// Each arrow is drawn for one animation interval with a minimum of one clear interval
|
|
|
|
// creating a clean flash on the display.
|
|
|
|
// Both arrows may appear in the same interval.
|
2018-12-01 18:25:10 +00:00
|
|
|
// The following is a typical sequence, relative to animation ticks, note the gap
|
2018-12-01 18:51:53 +00:00
|
|
|
// that always appears in the animation interval between either arrow shown:
|
2018-12-01 18:25:10 +00:00
|
|
|
//
|
2018-12-01 18:51:53 +00:00
|
|
|
// | | | | | | | | | | | | | | | | |
|
|
|
|
// _________^^^^^________________________________________^^^^^_________________________
|
|
|
|
// ______________vvvvv_____vvvvv_______________vvvvv_____vvvvv_____vvvvv_______________
|
2018-12-01 18:25:10 +00:00
|
|
|
|
|
|
|
bool
|
|
|
|
CScreenHeader::animate()
|
|
|
|
{
|
|
|
|
bool retval = false;
|
2018-12-02 06:30:40 +00:00
|
|
|
if((isWifiConnected() || isWifiAP()) && isWebClientConnected()) {
|
2018-12-01 19:14:34 +00:00
|
|
|
|
2018-12-01 18:25:10 +00:00
|
|
|
int xPos = X_WIFI_ICON + W_WIFI_ICON;
|
2018-12-02 06:30:40 +00:00
|
|
|
if(isWifiAP()) {
|
|
|
|
xPos += 4;
|
|
|
|
}
|
2018-12-01 18:51:53 +00:00
|
|
|
|
2018-12-01 19:14:34 +00:00
|
|
|
// UP arrow animation
|
2018-12-01 18:51:53 +00:00
|
|
|
//
|
2018-12-01 19:14:34 +00:00
|
|
|
int yPos = 0;
|
|
|
|
if(_clearUpAnimation) {
|
|
|
|
// arrow was drawn in the prior iteration, now erase it
|
|
|
|
_display.fillRect(xPos, yPos, W_WIFIIN_ICON, H_WIFIIN_ICON, BLACK);
|
2018-12-01 18:25:10 +00:00
|
|
|
retval = true;
|
2018-12-01 19:14:34 +00:00
|
|
|
_clearUpAnimation = false;
|
2018-12-01 18:25:10 +00:00
|
|
|
}
|
2018-12-01 19:14:34 +00:00
|
|
|
else if(hasWebServerSpoken(true)) {
|
|
|
|
// we have emitted data to the web client, show an UP arrow
|
|
|
|
_display.drawBitmap(xPos, yPos, wifiOutIcon, W_WIFIIN_ICON, H_WIFIIN_ICON, WHITE);
|
|
|
|
_clearUpAnimation = true; // clear arrow upon next iteration
|
2018-12-01 18:51:53 +00:00
|
|
|
retval = true;
|
|
|
|
}
|
|
|
|
|
2018-12-01 19:14:34 +00:00
|
|
|
// DOWN arrow animation
|
2018-12-01 18:51:53 +00:00
|
|
|
//
|
|
|
|
yPos = H_WIFI_ICON - H_WIFIIN_ICON + 1;
|
2018-12-01 19:14:34 +00:00
|
|
|
if(_clearDnAnimation) {
|
|
|
|
// arrow was drawn in the prior iteration, now erase it
|
|
|
|
_display.fillRect(xPos, yPos, W_WIFIOUT_ICON, H_WIFIOUT_ICON, BLACK);
|
2018-12-01 18:25:10 +00:00
|
|
|
retval = true;
|
2018-12-01 19:14:34 +00:00
|
|
|
_clearDnAnimation = false;
|
2018-12-01 18:25:10 +00:00
|
|
|
}
|
2018-12-01 19:14:34 +00:00
|
|
|
else if(hasWebClientSpoken(true)) {
|
|
|
|
// we have receievd data from the web client, show an DOWN arrow
|
|
|
|
_display.drawBitmap(xPos, yPos, wifiInIcon, W_WIFIOUT_ICON, H_WIFIOUT_ICON, WHITE);
|
|
|
|
_clearDnAnimation = true; // clear arrow upon next iteration
|
2018-12-01 18:25:10 +00:00
|
|
|
retval = true;
|
|
|
|
}
|
|
|
|
}
|
2018-12-01 19:14:34 +00:00
|
|
|
return retval; // true if we need to update the physical display
|
2018-12-01 18:25:10 +00:00
|
|
|
}
|
|
|
|
|
2018-12-01 00:36:25 +00:00
|
|
|
void
|
|
|
|
CScreenHeader::showBTicon()
|
|
|
|
{
|
2018-12-02 06:30:40 +00:00
|
|
|
if(getBluetoothClient().isConnected()) {
|
|
|
|
_display.drawBitmap(X_BT_ICON, Y_BT_ICON, BTicon, W_BT_ICON, H_BT_ICON, WHITE);
|
|
|
|
}
|
2018-12-01 00:36:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CScreenHeader::showWifiIcon()
|
|
|
|
{
|
2018-12-02 06:30:40 +00:00
|
|
|
if(isWifiConnected() || isWifiAP()) {
|
|
|
|
_display.drawBitmap(X_WIFI_ICON, Y_WIFI_ICON, wifiIcon, W_WIFI_ICON, H_WIFI_ICON, WHITE);
|
|
|
|
if(isWifiAP()) {
|
|
|
|
_display.fillRect(X_WIFI_ICON + 8, Y_WIFI_ICON + 5, 10, 7, BLACK);
|
|
|
|
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
|
|
|
|
_display.setCursor(X_WIFI_ICON+9, Y_WIFI_ICON+6);
|
|
|
|
_display.print("AP");
|
|
|
|
}
|
|
|
|
}
|
2018-12-01 00:36:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CScreenHeader::showBatteryIcon(float voltage)
|
|
|
|
{
|
|
|
|
_display.drawBitmap(X_BATT_ICON, Y_BATT_ICON, BatteryIcon, W_BATT_ICON, H_BATT_ICON, WHITE);
|
|
|
|
char msg[16];
|
|
|
|
sprintf(msg, "%.1fV", voltage);
|
|
|
|
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
|
|
|
|
_display.setCursor(X_BATT_ICON + W_BATT_ICON/2,
|
|
|
|
Y_BATT_ICON + H_BATT_ICON + 2);
|
|
|
|
_display.printCentreJustified(msg);
|
|
|
|
|
|
|
|
// nominal 10.5 -> 13.5V bargraph
|
|
|
|
int Capacity = (voltage - 10.7) * 4;
|
|
|
|
if(Capacity < 0) Capacity = 0;
|
|
|
|
if(Capacity > 11) Capacity = 11;
|
|
|
|
_display.fillRect(X_BATT_ICON+2 + Capacity, Y_BATT_ICON+2, W_BATT_ICON-4-Capacity, 6, BLACK);
|
|
|
|
}
|
|
|
|
|
2018-12-07 11:16:04 +00:00
|
|
|
int
|
|
|
|
CScreenHeader::showTimers()
|
|
|
|
{
|
|
|
|
sTimer timerInfo1;
|
|
|
|
sTimer timerInfo2;
|
|
|
|
|
|
|
|
NVstore.getTimerInfo(0, timerInfo1);
|
|
|
|
NVstore.getTimerInfo(1, timerInfo2);
|
|
|
|
|
|
|
|
int drawn = 0;
|
|
|
|
int xPos = X_TIMER2_ICON; // initially assume a single timer, locate to right of screen
|
|
|
|
|
|
|
|
if(timerInfo1.enabled) {
|
|
|
|
drawn++;
|
|
|
|
if(timerInfo2.enabled) // check if other timer is also enabled
|
|
|
|
xPos = X_TIMER1_ICON; // both are enabled - draw icon 1 to the left, otherwise leave to the right
|
|
|
|
_display.drawBitmap(xPos, Y_TIMER_ICON, timerID1Icon, W_TIMER_ICON, H_TIMER_ICON, WHITE);
|
|
|
|
if(timerInfo1.repeat)
|
|
|
|
_display.drawBitmap(xPos, Y_TIMER_ICON+1, repeatIcon, W_TIMER_ICON, H_TIMER_ICON, WHITE);
|
|
|
|
}
|
|
|
|
xPos = X_TIMER2_ICON; // logically the second icon attempt is always to the right!
|
|
|
|
if(timerInfo2.enabled) {
|
|
|
|
drawn++;
|
|
|
|
_display.drawBitmap(xPos, Y_TIMER_ICON, timerID2Icon, W_TIMER_ICON, H_TIMER_ICON, WHITE);
|
|
|
|
if(timerInfo2.repeat)
|
|
|
|
_display.drawBitmap(xPos, Y_TIMER_ICON+1, repeatIcon, W_TIMER_ICON, H_TIMER_ICON, WHITE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return drawn;
|
|
|
|
}
|
|
|
|
|
2018-12-01 00:36:25 +00:00
|
|
|
|
2018-12-07 11:16:04 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
CScreenHeader::showTime(int numTimers)
|
|
|
|
{
|
2018-12-08 22:51:16 +00:00
|
|
|
const BTCDateTime& now = Clock.get();
|
2018-12-07 22:30:55 +00:00
|
|
|
|
2018-12-07 11:16:04 +00:00
|
|
|
char msg[16];
|
|
|
|
if(now.second() & 0x01)
|
|
|
|
sprintf(msg, "%02d:%02d", now.hour(), now.minute());
|
|
|
|
else
|
|
|
|
sprintf(msg, "%02d %02d", now.hour(), now.minute());
|
|
|
|
{
|
|
|
|
CTransientFont AF(_display, &arial_8ptFontInfo);
|
|
|
|
// determine centre position of remaining real estate
|
|
|
|
int xPos = X_WIFI_ICON + W_WIFI_ICON + W_WIFIIN_ICON; // rhs of wifi conglomeration
|
|
|
|
if(isWifiAP()) xPos += 4; // add more if an Access Point
|
|
|
|
|
|
|
|
switch(numTimers) {
|
2018-12-07 22:30:55 +00:00
|
|
|
case 0: xPos = _display.xCentre(); break;
|
2018-12-07 11:16:04 +00:00
|
|
|
case 1: xPos += (X_TIMER2_ICON - xPos) / 2; break;
|
|
|
|
case 2: xPos += (X_TIMER1_ICON - xPos) / 2; break;
|
|
|
|
}
|
|
|
|
_printMenuText(xPos, Y_CLOCK, msg, false, eCentreJustify);
|
|
|
|
}
|
|
|
|
}
|