Pull wifi and IR into Hardware RevX

pull last bit of global variables into hardware rev
This commit is contained in:
Matthew Colvin 2023-07-29 08:58:13 -05:00
parent 98ecfb0de2
commit 21a703902f
5 changed files with 202 additions and 187 deletions

View file

@ -58,6 +58,18 @@ private:
int backlight_brightness = 255;
lv_color_t color_primary = lv_color_hex(0x303030); // gray
bool wakeupByIMUEnabled = true;
// TODO Figure out best way to have images added
// LV_IMG_DECLARE(gradientLeft);
// LV_IMG_DECLARE(gradientRight);
// LV_IMG_DECLARE(appleTvIcon);
// LV_IMG_DECLARE(appleDisplayIcon);
// LV_IMG_DECLARE(appleBackIcon);
// LV_IMG_DECLARE(high_brightness);
// LV_IMG_DECLARE(low_brightness);
// LV_IMG_DECLARE(lightbulb);
lv_img_dsc_t low_brightness;
lv_img_dsc_t high_brightness;
lv_img_dsc_t appleBackIcon;

View file

@ -4,6 +4,9 @@
// Comment out to disable connected features
#define ENABLE_WIFI
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
#define MQTT_SERVER "YOUR_MQTT_SERVER_IP"
// time until device enters sleep mode in milliseconds
#define SLEEP_TIMEOUT 20000

View file

@ -77,6 +77,7 @@ void HardwareRevX::init() {
setupBacklight();
setupTFT();
setupIMU();
setupIR();
initLVGL();
}
@ -362,3 +363,121 @@ void HardwareRevX::slowDisplayWakeup() {
delay(100); // Wait for the LCD driver to power on
}
void HardwareRevX::handleWifiEvent(WiFiEvent_t event){
// Serial.printf("[WiFi-event] event: %d\n", event);
if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) {
client.setServer(MQTT_SERVER, 1883); // MQTT initialization
client.connect("OMOTE"); // Connect using a client id
}
// Set status bar icon based on WiFi status
// TODO allow UI to register a Handler for these events
// if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP ||
// event == ARDUINO_EVENT_WIFI_STA_GOT_IP6) {
// lv_label_set_text(WifiLabel, LV_SYMBOL_WIFI);
// } else {
// lv_label_set_text(WifiLabel, "");
// }
}
void HardwareRevX::setupIR(){
// Setup IR
IrSender.begin();
digitalWrite(IR_VCC, HIGH); // Turn on IR receiver
IrReceiver.enableIRIn(); // Start the receiver
}
void HardwareRevX::setupWifi(){
#ifdef ENABLE_WIFI
// Setup WiFi
WiFi.setHostname("OMOTE"); // define hostname
WiFi.onEvent(WiFiEvent);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
WiFi.setSleep(true);
#endif
}
void HardwareRevX::handleLoop(){
// Update Backlight brightness
static int fadeInTimer = millis(); // fadeInTimer = time after setup
if (millis() <
fadeInTimer +
backlight_brightness) { // Fade in the backlight brightness
ledcWrite(5, millis() - fadeInTimer);
} else { // Dim Backlight before entering standby
if (standbyTimer < 2000)
ledcWrite(5, 85); // Backlight dim
else
ledcWrite(5, backlight_brightness); // Backlight on
}
// Update LVGL UI
lv_timer_handler();
// Blink debug LED at 1 Hz
digitalWrite(USER_LED, millis() % 1000 > 500);
// Refresh IMU data at 10Hz
static unsigned long IMUTaskTimer = millis();
if (millis() - IMUTaskTimer >= 100) {
activityDetection();
if (standbyTimer == 0) {
Serial.println("Entering Sleep Mode. Goodbye.");
enterSleep();
}
IMUTaskTimer = millis();
}
// Update battery stats at 1Hz
static unsigned long batteryTaskTimer =
millis() + 1000; // add 1s to start immediately
if (millis() - batteryTaskTimer >= 1000) {
battery_voltage =
analogRead(ADC_BAT) * 2 * 3300 / 4095 + 350; // 350mV ADC offset
battery_percentage =
constrain(map(battery_voltage, 3700, 4200, 0, 100), 0, 100);
batteryTaskTimer = millis();
battery_ischarging = !digitalRead(CRG_STAT);
// Check if battery is charging, fully charged or disconnected
}
// TODO Create batter change notification for UI
// if (battery_ischarging || (!battery_ischarging && battery_voltage > 4350)) {
// lv_label_set_text(objBattPercentage, "");
// lv_label_set_text(objBattIcon, LV_SYMBOL_USB);
// } else {
// // Update status bar battery indicator
// // lv_label_set_text_fmt(objBattPercentage, "%d%%", battery_percentage);
// if (battery_percentage > 95)
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_FULL);
// else if (battery_percentage > 75)
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_3);
// else if (battery_percentage > 50)
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_2);
// else if (battery_percentage > 25)
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_1);
// else
// lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_EMPTY);
// }
// }
// Keypad Handling
customKeypad.getKey(); // Populate key list
for (int i = 0; i < LIST_MAX; i++) { // Handle multiple keys (Not really necessary in this case)
if (customKeypad.key[i].kstate == PRESSED ||
customKeypad.key[i].kstate == HOLD) {
standbyTimer =
SLEEP_TIMEOUT; // Reset the sleep timer when a button is pressed
int keyCode = customKeypad.key[i].kcode;
Serial.println(customKeypad.key[i].kchar);
// Send IR codes depending on the current device (tabview page)
if (currentDevice == 1){
IrSender.sendRC5(IrSender.encodeRC5X(0x00, keyMapTechnisat[keyCode / ROWS][keyCode % ROWS]));
}
else if (currentDevice == 2){
IrSender.sendSony((keyCode / ROWS) * (keyCode % ROWS), 15);
}
}
}
}

View file

@ -6,8 +6,14 @@
#include "Wire.h"
#include "lvgl.h"
#include <Adafruit_FT6206.h>
#include <IRrecv.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <IRutils.h>
#include <PubSubClient.h>
#include <Preferences.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <Keypad.h> // modified for inverted logic
#include <functional>
#include <memory>
@ -23,6 +29,9 @@ public:
}
return mInstance;
}
static std::weak_ptr<HardwareRevX> getRefrence(){
return getInstance();
}
HardwareRevX() : HardwareAbstractionInterface(){};
@ -63,7 +72,17 @@ public:
void slowDisplayWakeup();
void setupWifi();
void setupIR();
void handleWifiEvent(WiFiEvent_t event);
public:
static void WiFiEvent(WiFiEvent_t event){
mInstance->handleWifiEvent(event);
}
static void displayFlushImpl(lv_disp_drv_t *disp, const lv_area_t *area,
lv_color_t *color_p) {
mInstance->displayFlush(disp, area, color_p);
@ -73,7 +92,8 @@ public:
mInstance->touchPadRead(indev_driver, data);
}
int standbyTimer = SLEEP_TIMEOUT;
WiFiClient espClient;
PubSubClient client = PubSubClient(espClient);
Adafruit_FT6206 touch = Adafruit_FT6206();
TS_Point touchPoint;
@ -83,6 +103,7 @@ public:
// IMU Motion Detection
LIS3DH IMU = LIS3DH(I2C_MODE, 0x19); // Default constructor is I2C, addr 0x19.
int standbyTimer = SLEEP_TIMEOUT;
int motion = 0;
WakeReason wakeup_reason;
@ -92,10 +113,51 @@ public:
byte currentDevice = 1; // Current Device to control (allows switching
// mappings between devices)
// IR declarations
IRsend IrSender = IRsend(IR_LED, true);
IRrecv IrReceiver = IRrecv(IR_RX);
int battery_voltage = 0;
int battery_percentage = 100;
bool battery_ischarging = false;
// LVGL Screen Buffers
lv_disp_draw_buf_t mdraw_buf;
lv_color_t mbufA[SCREEN_WIDTH * SCREEN_HEIGHT / 10];
lv_color_t mbufB[SCREEN_WIDTH * SCREEN_HEIGHT / 10];
lv_color_t color_primary = lv_color_hex(0x303030); // gray
// Keypad declarations
static const byte ROWS = 5; // four rows
static const byte COLS = 5; // four columns
// define the symbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
{'s', '^', '-', 'm', 'r'}, // source, channel+, Volume-, mute, record
{'i', 'r', '+', 'k', 'd'}, // info, right, Volume+, OK, down
{'4', 'v', '1', '3', '2'}, // blue, channel-, red, yellow, green
{'>', 'o', 'b', 'u', 'l'}, // forward, off, back, up, left
{'?', 'p', 'c', '<', '='} // ?, play, config, rewind, stop
};
byte rowPins[ROWS] = {SW_A, SW_B, SW_C, SW_D,
SW_E}; // connect to the row pinouts of the keypad
byte colPins[COLS] = {SW_1, SW_2, SW_3, SW_4,
SW_5}; // connect to the column pinouts of the keypad
Keypad customKeypad =
Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
byte keyMapTechnisat[ROWS][COLS] = {{0x69, 0x20, 0x11, 0x0D, 0x56},
{0x4F, 0x37, 0x10, 0x57, 0x51},
{0x6E, 0x21, 0x6B, 0x6D, 0x6C},
{0x34, 0x0C, 0x22, 0x50, 0x55},
{'?', 0x35, 0x2F, 0x32, 0x36}};
byte virtualKeyMapTechnisat[10] = {0x1, 0x2, 0x3, 0x4, 0x5,
0x6, 0x7, 0x8, 0x9, 0x0};
static std::shared_ptr<HardwareRevX> mInstance;
};

View file

@ -1,102 +1,14 @@
// OMOTE firmware for ESP32
// 2023 Maximilian Kern
#include <IRrecv.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <IRutils.h>
#include <Keypad.h> // modified for inverted logic
#include <PubSubClient.h>
#include <lvgl.h>
#include <lvgl.h>
#include "HardwareRevX.hpp"
#include "OmoteUI/OmoteUI.hpp"
#include "omoteconfig.h"
std::shared_ptr<HardwareRevX> hal = nullptr;
int battery_voltage = 0;
int battery_percentage = 100;
bool battery_ischarging = false;
// LCD declarations
// LVGL declarations
lv_obj_t *objBattPercentage;
lv_obj_t *objBattIcon;
LV_IMG_DECLARE(gradientLeft);
LV_IMG_DECLARE(gradientRight);
LV_IMG_DECLARE(appleTvIcon);
LV_IMG_DECLARE(appleDisplayIcon);
LV_IMG_DECLARE(appleBackIcon);
LV_IMG_DECLARE(high_brightness);
LV_IMG_DECLARE(low_brightness);
LV_IMG_DECLARE(lightbulb);
lv_obj_t *panel;
lv_color_t color_primary = lv_color_hex(0x303030); // gray
// Keypad declarations
const byte ROWS = 5; // four rows
const byte COLS = 5; // four columns
// define the symbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
{'s', '^', '-', 'm', 'r'}, // source, channel+, Volume-, mute, record
{'i', 'r', '+', 'k', 'd'}, // info, right, Volume+, OK, down
{'4', 'v', '1', '3', '2'}, // blue, channel-, red, yellow, green
{'>', 'o', 'b', 'u', 'l'}, // forward, off, back, up, left
{'?', 'p', 'c', '<', '='} // ?, play, config, rewind, stop
};
byte rowPins[ROWS] = {SW_A, SW_B, SW_C, SW_D,
SW_E}; // connect to the row pinouts of the keypad
byte colPins[COLS] = {SW_1, SW_2, SW_3, SW_4,
SW_5}; // connect to the column pinouts of the keypad
Keypad customKeypad =
Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
byte keyMapTechnisat[ROWS][COLS] = {{0x69, 0x20, 0x11, 0x0D, 0x56},
{0x4F, 0x37, 0x10, 0x57, 0x51},
{0x6E, 0x21, 0x6B, 0x6D, 0x6C},
{0x34, 0x0C, 0x22, 0x50, 0x55},
{'?', 0x35, 0x2F, 0x32, 0x36}};
byte virtualKeyMapTechnisat[10] = {0x1, 0x2, 0x3, 0x4, 0x5,
0x6, 0x7, 0x8, 0x9, 0x0};
// IR declarations
IRsend IrSender(IR_LED, true);
IRrecv IrReceiver(IR_RX);
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
#define MQTT_SERVER "YOUR_MQTT_SERVER_IP"
lv_obj_t *WifiLabel;
WiFiClient espClient;
PubSubClient client(espClient);
// Helper Functions
// -----------------------------------------------------------------------------------------------------------------------
#ifdef ENABLE_WIFI
// WiFi status event
void WiFiEvent(WiFiEvent_t event) {
// Serial.printf("[WiFi-event] event: %d\n", event);
if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) {
client.setServer(MQTT_SERVER, 1883); // MQTT initialization
client.connect("OMOTE"); // Connect using a client id
}
// Set status bar icon based on WiFi status
if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP ||
event == ARDUINO_EVENT_WIFI_STA_GOT_IP6) {
lv_label_set_text(WifiLabel, LV_SYMBOL_WIFI);
} else {
lv_label_set_text(WifiLabel, "");
}
}
#endif
// Setup
// ----------------------------------------------------------------------------------------------------------------------------------
void setup() {
hal = HardwareRevX::getInstance();
@ -105,18 +17,6 @@ void setup() {
auto ui = OmoteUI::getInstance(hal);
ui->layout_UI();
#ifdef ENABLE_WIFI
// Setup WiFi
WiFi.setHostname("OMOTE"); // define hostname
WiFi.onEvent(WiFiEvent);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
WiFi.setSleep(true);
#endif
// Setup IR
IrSender.begin();
digitalWrite(IR_VCC, HIGH); // Turn on IR receiver
IrReceiver.enableIRIn(); // Start the receiver
lv_timer_handler(); // Run the LVGL UI once before the loop takes over
@ -125,95 +25,14 @@ void setup() {
Serial.println("ms.");
}
// Loop
// ------------------------------------------------------------------------------------------------------------------------------------
void loop() {
// Update Backlight brightness
static int fadeInTimer = millis(); // fadeInTimer = time after setup
if (millis() <
fadeInTimer +
hal->backlight_brightness) { // Fade in the backlight brightness
ledcWrite(5, millis() - fadeInTimer);
} else { // Dim Backlight before entering standby
if (hal->standbyTimer < 2000)
ledcWrite(5, 85); // Backlight dim
else
ledcWrite(5, hal->backlight_brightness); // Backlight on
}
// Update LVGL UI
lv_timer_handler();
// Blink debug LED at 1 Hz
digitalWrite(USER_LED, millis() % 1000 > 500);
// Refresh IMU data at 10Hz
static unsigned long IMUTaskTimer = millis();
if (millis() - IMUTaskTimer >= 100) {
hal->activityDetection();
if (hal->standbyTimer == 0) {
Serial.println("Entering Sleep Mode. Goodbye.");
hal->enterSleep();
}
IMUTaskTimer = millis();
}
// Update battery stats at 1Hz
static unsigned long batteryTaskTimer =
millis() + 1000; // add 1s to start immediately
if (millis() - batteryTaskTimer >= 1000) {
battery_voltage =
analogRead(ADC_BAT) * 2 * 3300 / 4095 + 350; // 350mV ADC offset
battery_percentage =
constrain(map(battery_voltage, 3700, 4200, 0, 100), 0, 100);
batteryTaskTimer = millis();
battery_ischarging = !digitalRead(CRG_STAT);
// Check if battery is charging, fully charged or disconnected
if (battery_ischarging || (!battery_ischarging && battery_voltage > 4350)) {
lv_label_set_text(objBattPercentage, "");
lv_label_set_text(objBattIcon, LV_SYMBOL_USB);
} else {
// Update status bar battery indicator
// lv_label_set_text_fmt(objBattPercentage, "%d%%", battery_percentage);
if (battery_percentage > 95)
lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_FULL);
else if (battery_percentage > 75)
lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_3);
else if (battery_percentage > 50)
lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_2);
else if (battery_percentage > 25)
lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_1);
else
lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_EMPTY);
}
}
// Keypad Handling
customKeypad.getKey(); // Populate key list
for (int i = 0; i < LIST_MAX;
i++) { // Handle multiple keys (Not really necessary in this case)
if (customKeypad.key[i].kstate == PRESSED ||
customKeypad.key[i].kstate == HOLD) {
hal->standbyTimer =
SLEEP_TIMEOUT; // Reset the sleep timer when a button is pressed
int keyCode = customKeypad.key[i].kcode;
Serial.println(customKeypad.key[i].kchar);
// Send IR codes depending on the current device (tabview page)
if (hal->currentDevice == 1)
IrSender.sendRC5(IrSender.encodeRC5X(
0x00, keyMapTechnisat[keyCode / ROWS][keyCode % ROWS]));
else if (hal->currentDevice == 2)
IrSender.sendSony((keyCode / ROWS) * (keyCode % ROWS), 15);
}
}
HardwareRevX::getInstance()->handleLoop();
// IR Test
// tft.drawString("IR Command: ", 10, 90, 1);
// decode_results results;
// if (IrReceiver.decode(&results)) {
// //tft.drawString(String(results.command) + " ", 80, 90, 1);
// IrReceiver.resume(); // Enable receiving of the next value
//}
// IrReceiver.resume(); // Enable receiving of the next value
//} //tft.drawString(String(results.command) + " ", 80, 90, 1);
//
}