26 Commits

Author SHA1 Message Date
suchmememanyskill
2a2fff27d6 Merge branch 'master' into dev 2024-01-19 21:10:39 +01:00
suchmememanyskill
082d66ca10 Longer watchdog timeout, refactor, use duty cycle for backlight 2024-01-19 21:05:57 +01:00
Sims
41b4bff940 Merge pull request #12 from suchmememanyskill/dev
Dev
2024-01-15 13:28:57 +01:00
suchmememanyskill
9136f4c94b Add some delay within data loop to give other processes on the core time to process 2024-01-08 21:33:01 +01:00
suchmememanyskill
50f4984231 Insert sort the fetched files, discard any extras 2024-01-07 21:07:35 +01:00
suchmememanyskill
48466cfb44 Lower data fetch task priority 2024-01-07 21:07:19 +01:00
suchmememanyskill
a7acd49d60 Make all colors somewhat worth using 2024-01-06 20:40:37 +01:00
suchmememanyskill
91920a679a Fix #10 2024-01-06 19:59:13 +01:00
suchmememanyskill
53441c86c4 Add kofi to site 2024-01-05 23:20:47 +01:00
Sims
ffdc8ae87e Merge pull request #7 from suchmememanyskill/dev
v1.1.2
2023-12-16 17:53:14 +01:00
suchmememanyskill
7c786d1e6b Don't continously call unfreeze_render_thread() 2023-12-15 19:24:55 +01:00
suchmememanyskill
34c6a5e031 Offload API request loop to core 0 2023-12-15 19:22:48 +01:00
suchmememanyskill
7a430f81c5 Change back to klipper connect screen when connection to klipper gets severed 2023-12-11 22:23:18 +01:00
Sims
230884c2cc Merge pull request #6 from suchmememanyskill/dev
V1.1.1
2023-12-03 01:25:45 +01:00
suchmememanyskill
f2d232d9eb Add visual Klipper connect retry 2023-12-02 02:01:26 +01:00
suchmememanyskill
1e3f0ab637 Lower CPU speed if screen is off 2023-12-02 01:13:40 +01:00
suchmememanyskill
e15c7e37ff update readme 2023-11-23 12:31:32 +01:00
suchmememanyskill
e15ba8d852 Merge branch 'dev' 2023-11-23 12:01:12 +01:00
suchmememanyskill
a759ccbbf7 Merge branch 'master' of https://github.com/suchmememanyskill/CYD-Klipper-Display 2023-11-23 12:01:09 +01:00
suchmememanyskill
84662a8fab Make sure the macro name doesn't overflow 2023-11-23 11:58:10 +01:00
suchmememanyskill
cb47286784 Add macro support 2023-11-23 11:46:09 +01:00
suchmememanyskill
6717e53fc9 Fix filenames with spaces 2023-11-23 10:43:39 +01:00
suchmememanyskill
dc5a3b5efd Add temp presets 2023-11-21 04:01:35 +01:00
Sims
48520f652a Print wifi connect status while connecting, retry ip more times (#3) 2023-11-20 15:57:40 +01:00
suchmememanyskill
dccb10cc6f Print wifi connect status while connecting, retry ip more times 2023-11-14 00:45:08 +01:00
suchmememanyskill
c5d08253a7 Retry IP connect on boot, fix network c string issue 2023-11-14 00:31:52 +01:00
23 changed files with 635 additions and 126 deletions

View File

@@ -8,6 +8,7 @@
"unordered_set": "cpp", "unordered_set": "cpp",
"vector": "cpp", "vector": "cpp",
"string_view": "cpp", "string_view": "cpp",
"initializer_list": "cpp" "initializer_list": "cpp",
"algorithm": "cpp"
} }
} }

View File

@@ -18,7 +18,8 @@ lib_deps =
lvgl/lvgl@^8.3.9 lvgl/lvgl@^8.3.9
https://github.com/Bodmer/TFT_eSPI.git https://github.com/Bodmer/TFT_eSPI.git
https://github.com/PaulStoffregen/XPT2046_Touchscreen.git https://github.com/PaulStoffregen/XPT2046_Touchscreen.git
bblanchon/ArduinoJson@^6.21.3 bblanchon/ArduinoJson@^7.0.0
monitor_filters = esp32_exception_decoder
build_flags = build_flags =
-DLV_CONF_PATH="../../../../src/conf/lv_conf.h" -DLV_CONF_PATH="../../../../src/conf/lv_conf.h"
-DUSER_SETUP_LOADED=1 -DUSER_SETUP_LOADED=1

View File

@@ -5,13 +5,13 @@
GLOBAL_CONFIG global_config = {0}; GLOBAL_CONFIG global_config = {0};
COLOR_DEF color_defs[] = { COLOR_DEF color_defs[] = {
{LV_PALETTE_BLUE, LV_PALETTE_RED}, {LV_PALETTE_BLUE, 0, LV_PALETTE_RED},
{LV_PALETTE_GREEN, LV_PALETTE_PURPLE}, {LV_PALETTE_LIME, -2, LV_PALETTE_PURPLE},
{LV_PALETTE_GREY, LV_PALETTE_CYAN}, {LV_PALETTE_GREY, 0, LV_PALETTE_CYAN},
{LV_PALETTE_YELLOW, LV_PALETTE_PINK}, {LV_PALETTE_YELLOW, -2, LV_PALETTE_PINK},
{LV_PALETTE_ORANGE, LV_PALETTE_BLUE}, {LV_PALETTE_ORANGE, -2, LV_PALETTE_BLUE},
{LV_PALETTE_RED, LV_PALETTE_GREEN}, {LV_PALETTE_RED, 0, LV_PALETTE_GREEN},
{LV_PALETTE_PURPLE, LV_PALETTE_GREY}, {LV_PALETTE_PURPLE, 0, LV_PALETTE_GREY},
}; };
void WriteGlobalConfig() { void WriteGlobalConfig() {
@@ -41,6 +41,12 @@ void LoadGlobalConfig() {
global_config.version = CONFIG_VERSION; global_config.version = CONFIG_VERSION;
global_config.brightness = 255; global_config.brightness = 255;
global_config.screenTimeout = 5; global_config.screenTimeout = 5;
global_config.hotend_presets[0] = 0;
global_config.hotend_presets[1] = 200;
global_config.hotend_presets[2] = 240;
global_config.bed_presets[0] = 0;
global_config.bed_presets[1] = 60;
global_config.bed_presets[2] = 70;
VerifyVersion(); VerifyVersion();
Preferences preferences; Preferences preferences;
preferences.begin("global_config", true); preferences.begin("global_config", true);

View File

@@ -3,16 +3,19 @@
#include "lvgl.h" #include "lvgl.h"
#define CONFIG_VERSION 2 #define CONFIG_VERSION 3
typedef struct _GLOBAL_CONFIG { typedef struct _GLOBAL_CONFIG {
unsigned char version; unsigned char version;
union { union {
unsigned char raw; unsigned char raw;
struct { struct {
// Internal
bool screenCalibrated : 1; bool screenCalibrated : 1;
bool wifiConfigured : 1; bool wifiConfigured : 1;
bool ipConfigured : 1; bool ipConfigured : 1;
// External
bool lightMode : 1; bool lightMode : 1;
bool invertColors : 1; bool invertColors : 1;
bool rotateScreen : 1; bool rotateScreen : 1;
@@ -33,10 +36,14 @@ typedef struct _GLOBAL_CONFIG {
unsigned char color_scheme; unsigned char color_scheme;
unsigned char brightness; unsigned char brightness;
unsigned char screenTimeout; unsigned char screenTimeout;
unsigned short hotend_presets[3];
unsigned short bed_presets[3];
} GLOBAL_CONFIG; } GLOBAL_CONFIG;
typedef struct _COLOR_DEF { typedef struct _COLOR_DEF {
lv_palette_t primary_color; lv_palette_t primary_color;
short primary_color_light;
lv_palette_t secondary_color; lv_palette_t secondary_color;
} COLOR_DEF; } COLOR_DEF;

View File

@@ -4,6 +4,8 @@
#include "../conf/global_config.h" #include "../conf/global_config.h"
#include <HTTPClient.h> #include <HTTPClient.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <esp_task_wdt.h>
#include "macros_query.h"
const char *printer_state_messages[] = { const char *printer_state_messages[] = {
"Error", "Error",
@@ -11,6 +13,33 @@ const char *printer_state_messages[] = {
"Printing"}; "Printing"};
Printer printer = {0}; Printer printer = {0};
int klipper_request_consecutive_fail_count = 0;
char filename_buff[512] = {0};
SemaphoreHandle_t freezeRenderThreadSemaphore, freezeRequestThreadSemaphore;
const long data_update_interval = 780;
void semaphore_init(){
freezeRenderThreadSemaphore = xSemaphoreCreateMutex();
freezeRequestThreadSemaphore = xSemaphoreCreateMutex();
xSemaphoreGive(freezeRenderThreadSemaphore);
xSemaphoreGive(freezeRequestThreadSemaphore);
}
void freeze_request_thread(){
xSemaphoreTake(freezeRequestThreadSemaphore, portMAX_DELAY);
}
void unfreeze_request_thread(){
xSemaphoreGive(freezeRequestThreadSemaphore);
}
void freeze_render_thread(){
xSemaphoreTake(freezeRenderThreadSemaphore, portMAX_DELAY);
}
void unfreeze_render_thread(){
xSemaphoreGive(freezeRenderThreadSemaphore);
}
void send_gcode(bool wait, const char *gcode) void send_gcode(bool wait, const char *gcode)
{ {
@@ -34,23 +63,27 @@ void send_gcode(bool wait, const char *gcode)
} }
} }
char filename_buff[512] = {0};
void fetch_printer_data() void fetch_printer_data()
{ {
freeze_request_thread();
char buff[256] = {}; char buff[256] = {};
sprintf(buff, "http://%s:%d/printer/objects/query?extruder&heater_bed&toolhead&gcode_move&virtual_sdcard&print_stats&webhooks", global_config.klipperHost, global_config.klipperPort); sprintf(buff, "http://%s:%d/printer/objects/query?extruder&heater_bed&toolhead&gcode_move&virtual_sdcard&print_stats&webhooks", global_config.klipperHost, global_config.klipperPort);
HTTPClient client; HTTPClient client;
client.useHTTP10(true);
client.begin(buff); client.begin(buff);
int httpCode = client.GET(); int httpCode = client.GET();
delay(10);
if (httpCode == 200) if (httpCode == 200)
{ {
String payload = client.getString(); klipper_request_consecutive_fail_count = 0;
DynamicJsonDocument doc(4096); JsonDocument doc;
deserializeJson(doc, payload); deserializeJson(doc, client.getStream());
auto status = doc["result"]["status"]; auto status = doc["result"]["status"];
bool emit_state_update = false; bool emit_state_update = false;
int printer_state = printer.state; int printer_state = printer.state;
delay(10);
unfreeze_request_thread();
freeze_render_thread();
if (status.containsKey("webhooks")) if (status.containsKey("webhooks"))
{ {
@@ -155,28 +188,41 @@ void fetch_printer_data()
printer.state = printer_state; printer.state = printer_state;
lv_msg_send(DATA_PRINTER_STATE, &printer); lv_msg_send(DATA_PRINTER_STATE, &printer);
} }
unfreeze_render_thread();
} }
else else
{ {
klipper_request_consecutive_fail_count++;
Serial.printf("Failed to fetch printer data: %d\n", httpCode); Serial.printf("Failed to fetch printer data: %d\n", httpCode);
unfreeze_request_thread();
} }
} }
long last_data_update = 0;
const long data_update_interval = 1500;
void data_loop() void data_loop()
{ {
if (millis() - last_data_update < data_update_interval) // Causes other threads that are trying to lock the thread to actually lock it
return; unfreeze_render_thread();
delay(1);
last_data_update = millis(); freeze_render_thread();
fetch_printer_data();
} }
void data_loop_background(void * param){
esp_task_wdt_init(10, true);
while (true){
delay(data_update_interval);
fetch_printer_data();
}
}
TaskHandle_t background_loop;
void data_setup() void data_setup()
{ {
semaphore_init();
printer.print_filename = filename_buff; printer.print_filename = filename_buff;
fetch_printer_data(); fetch_printer_data();
macros_query_setup();
freeze_render_thread();
xTaskCreatePinnedToCore(data_loop_background, "data_loop_background", 5000, NULL, 0, &background_loop, 0);
} }

View File

@@ -28,10 +28,15 @@ typedef struct _Printer {
} Printer; } Printer;
extern Printer printer; extern Printer printer;
extern int klipper_request_consecutive_fail_count;
#define DATA_PRINTER_STATE 1 #define DATA_PRINTER_STATE 1
#define DATA_PRINTER_DATA 2 #define DATA_PRINTER_DATA 2
#define DATA_PRINTER_TEMP_PRESET 3
void data_loop(); void data_loop();
void data_setup(); void data_setup();
void send_gcode(bool wait, const char* gcode); void send_gcode(bool wait, const char* gcode);
void freeze_request_thread();
void unfreeze_request_thread();

View File

@@ -1,6 +1,7 @@
#include <list> #include <list>
#include "files_query.h" #include "files_query.h"
#include "../conf/global_config.h" #include "../conf/global_config.h"
#include "data_setup.h"
#include <HTTPClient.h> #include <HTTPClient.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <HardwareSerial.h> #include <HardwareSerial.h>
@@ -8,7 +9,9 @@
// Always has +1 entry with a null'd name // Always has +1 entry with a null'd name
FILESYSTEM_FILE* last_query = NULL; FILESYSTEM_FILE* last_query = NULL;
FILESYSTEM_FILE* get_files(){ FILESYSTEM_FILE* get_files(int limit){
freeze_request_thread();
if (last_query != NULL){ if (last_query != NULL){
FILESYSTEM_FILE* current = last_query; FILESYSTEM_FILE* current = last_query;
@@ -20,37 +23,76 @@ FILESYSTEM_FILE* get_files(){
free(last_query); free(last_query);
} }
Serial.printf("Heap space pre-file-parse: %d bytes\n", esp_get_free_heap_size());
std::list<FILESYSTEM_FILE> files; std::list<FILESYSTEM_FILE> files;
auto timer_request = millis();
char buff[256] = {}; char buff[256] = {};
sprintf(buff, "http://%s:%d/server/files/list", global_config.klipperHost, global_config.klipperPort); sprintf(buff, "http://%s:%d/server/files/list", global_config.klipperHost, global_config.klipperPort);
HTTPClient client; HTTPClient client;
client.useHTTP10(true);
client.begin(buff); client.begin(buff);
int httpCode = client.GET(); int httpCode = client.GET();
int count = 0; auto timer_parse = millis();
if (httpCode == 200){ if (httpCode == 200){
String payload = client.getString(); JsonDocument doc;
DynamicJsonDocument doc(60000); auto parseResult = deserializeJson(doc, client.getStream());
auto a = deserializeJson(doc, payload); Serial.printf("Json parse: %s\n", parseResult.c_str());
Serial.printf("JSON PARSE: %s\n", a.c_str());
auto result = doc["result"].as<JsonArray>(); auto result = doc["result"].as<JsonArray>();
for (auto file : result){ for (auto file : result){
FILESYSTEM_FILE f = {0}; FILESYSTEM_FILE f = {0};
const char* path = file["path"]; const char* path = file["path"];
f.name = (char*)malloc(strlen(path) + 1); float modified = file["modified"];
strcpy(f.name, path); auto file_iter = files.begin();
f.modified = file["modified"];
files.push_back(f); while (file_iter != files.end()){
count++; if ((*file_iter).modified < modified)
} break;
file_iter++;
} }
//Serial.printf("Found %d files\n", count); // Little inefficient as it always allocates a string, even if it doesn't have to
files.sort([](FILESYSTEM_FILE a, FILESYSTEM_FILE b){return a.modified < b.modified;}); f.name = (char*)malloc(strlen(path) + 1);
files.reverse(); // TODO: Reverse is unneeded here, we can iterate backwards if (f.name == NULL){
Serial.println("Failed to allocate memory");
continue;
}
strcpy(f.name, path);
f.modified = modified;
if (file_iter != files.end())
files.insert(file_iter, f);
else
files.push_back(f);
if (files.size() > limit){
auto last_entry = files.back();
if (last_entry.name != NULL)
free(last_entry.name);
files.pop_back();
}
}
}
size_t size = sizeof(FILESYSTEM_FILE) * (files.size() + 1); size_t size = sizeof(FILESYSTEM_FILE) * (files.size() + 1);
FILESYSTEM_FILE* result = (FILESYSTEM_FILE*)malloc(size); FILESYSTEM_FILE* result = (FILESYSTEM_FILE*)malloc(size);
//Serial.printf("Allocated %d bytes\n", size);
if (result == NULL){
Serial.println("Failed to allocate memory");
for (auto file : files){
free(file.name);
}
unfreeze_request_thread();
return NULL;
}
last_query = result; last_query = result;
result[files.size()].name = NULL; result[files.size()].name = NULL;
@@ -59,5 +101,8 @@ FILESYSTEM_FILE* get_files(){
result += 1; result += 1;
} }
Serial.printf("Heap space post-file-parse: %d bytes\n", esp_get_free_heap_size());
Serial.printf("Got %d files. Request took %dms, parsing took %dms\n", files.size(), timer_parse - timer_request, millis() - timer_parse);
unfreeze_request_thread();
return last_query; return last_query;
} }

View File

@@ -19,4 +19,4 @@ typedef struct _FILESYSTEM_FILE {
float modified; float modified;
} FILESYSTEM_FILE; } FILESYSTEM_FILE;
FILESYSTEM_FILE* get_files(); FILESYSTEM_FILE* get_files(int limit);

View File

@@ -0,0 +1,51 @@
#include "lvgl.h"
#include "macros_query.h"
#include "./data_setup.h"
#include <HTTPClient.h>
#include "../conf/global_config.h"
#include <ArduinoJson.h>
static char* macros[64] = {0};
static int macros_count = 0;
static void on_state_change(void * s, lv_msg_t * m) {
if (printer.state == PRINTER_STATE_ERROR || printer.state == PRINTER_STATE_PAUSED){
return;
}
String url = "http://" + String(global_config.klipperHost) + ":" + String(global_config.klipperPort) + "/printer/gcode/help";
HTTPClient client;
client.useHTTP10(true);
client.begin(url.c_str());
int httpCode = client.GET();
if (httpCode == 200){
JsonDocument doc;
deserializeJson(doc, client.getStream());
auto result = doc["result"].as<JsonObject>();
for (int i = 0; i < macros_count; i++){
free(macros[i]);
}
macros_count = 0;
for (JsonPair i : result){
const char *key = i.key().c_str();
const char *value = i.value().as<String>().c_str();
if (strcmp(value, "CYD_SCREEN_MACRO") == 0) {
char* macro = (char*)malloc(strlen(key) + 1);
strcpy(macro, key);
macros[macros_count++] = macro;
}
}
}
}
MACROSQUERY macros_query() {
return {(const char**)macros, macros_count};
}
void macros_query_setup(){
lv_msg_subscribe(DATA_PRINTER_STATE, on_state_change, NULL);
on_state_change(NULL, NULL);
}

View File

@@ -0,0 +1,9 @@
#pragma once
typedef struct {
const char** macros;
uint32_t count;
} MACROSQUERY;
MACROSQUERY macros_query();
void macros_query_setup();

View File

@@ -84,7 +84,11 @@ void touchscreen_calibrate(bool force)
void screen_setBrightness(byte brightness) void screen_setBrightness(byte brightness)
{ {
analogWrite(TFT_BL, brightness); // calculate duty, 4095 from 2 ^ 12 - 1
uint32_t duty = (4095 / 255) * brightness;
// write duty to LEDC
ledcWrite(0, duty);
} }
void set_screen_brightness() void set_screen_brightness()
@@ -100,12 +104,20 @@ void screen_timer_wake()
lv_timer_reset(screenSleepTimer); lv_timer_reset(screenSleepTimer);
isScreenInSleep = false; isScreenInSleep = false;
set_screen_brightness(); set_screen_brightness();
// Reset cpu freq
setCpuFrequencyMhz(CPU_FREQ_HIGH);
Serial.printf("CPU Speed: %d MHz\n", ESP.getCpuFreqMHz());
} }
void screen_timer_sleep(lv_timer_t *timer) void screen_timer_sleep(lv_timer_t *timer)
{ {
screen_setBrightness(0); screen_setBrightness(0);
isScreenInSleep = true; isScreenInSleep = true;
// Screen is off, no need to make the cpu run fast, the user won't notice ;)
setCpuFrequencyMhz(CPU_FREQ_LOW);
Serial.printf("CPU Speed: %d MHz\n", ESP.getCpuFreqMHz());
} }
void screen_timer_setup() void screen_timer_setup()
@@ -175,7 +187,20 @@ void screen_lv_touchRead(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
void set_color_scheme(){ void set_color_scheme(){
lv_disp_t *dispp = lv_disp_get_default(); lv_disp_t *dispp = lv_disp_get_default();
lv_theme_t *theme = lv_theme_default_init(dispp, lv_palette_main(color_defs[global_config.color_scheme].primary_color), lv_palette_main(color_defs[global_config.color_scheme].secondary_color), !global_config.lightMode, LV_FONT_DEFAULT); lv_color_t main_color = {0};
COLOR_DEF color_def = color_defs[global_config.color_scheme];
if (color_defs[global_config.color_scheme].primary_color_light > 0){
main_color = lv_palette_lighten(color_def.primary_color, color_def.primary_color_light);
}
else if (color_defs[global_config.color_scheme].primary_color_light < 0) {
main_color = lv_palette_darken(color_def.primary_color, color_def.primary_color_light * -1);
}
else {
main_color = lv_palette_main(color_defs[global_config.color_scheme].primary_color);
}
lv_theme_t *theme = lv_theme_default_init(dispp, main_color, lv_palette_main(color_def.secondary_color), !global_config.lightMode, LV_FONT_DEFAULT);
lv_disp_set_theme(dispp, theme); lv_disp_set_theme(dispp, theme);
} }
@@ -192,6 +217,10 @@ void screen_setup()
lv_init(); lv_init();
tft.init(); tft.init();
ledcSetup(0, 5000, 12);
ledcAttachPin(21, 0);
tft.setRotation(global_config.rotateScreen ? 3 : 1); tft.setRotation(global_config.rotateScreen ? 3 : 1);
tft.fillScreen(TFT_BLACK); tft.fillScreen(TFT_BLACK);
set_screen_brightness(); set_screen_brightness();

View File

@@ -4,6 +4,9 @@
#ifndef _SCREEN_DRIVER_INIT #ifndef _SCREEN_DRIVER_INIT
#define _SCREEN_DRIVER_INIT #define _SCREEN_DRIVER_INIT
#define CPU_FREQ_HIGH 240
#define CPU_FREQ_LOW 80
#include <XPT2046_Touchscreen.h> #include <XPT2046_Touchscreen.h>
#include <TFT_eSPI.h> #include <TFT_eSPI.h>

View File

@@ -25,37 +25,16 @@ void setup() {
Serial.println("Screen init done"); Serial.println("Screen init done");
wifi_init(); wifi_init();
ip_setup(); ip_init();
data_setup(); data_setup();
nav_style_setup(); nav_style_setup();
main_ui_setup(); main_ui_setup();
/*
lv_obj_clean(lv_scr_act());
lv_obj_t * label;
lv_obj_t * btn1 = lv_btn_create(lv_scr_act());
lv_obj_add_event_cb(btn1, event_handler, LV_EVENT_CLICKED, NULL);
lv_obj_align(btn1, LV_ALIGN_CENTER, 0, 0);
label = lv_label_create(btn1);
lv_label_set_text(label, "Reset Configuration");
lv_obj_center(label);
lv_obj_t * slider = lv_slider_create(lv_scr_act());
lv_obj_set_width(slider, 200);
lv_obj_align(slider, LV_ALIGN_CENTER, 0, 40);
lv_slider_set_range(slider, 0, 100);
lv_slider_set_value(slider, 50, LV_ANIM_OFF);
*/
} }
void loop(){ void loop(){
wifi_ok(); wifi_ok();
ip_ok();
data_loop(); data_loop();
lv_timer_handler(); lv_timer_handler();
lv_task_handler(); lv_task_handler();

View File

@@ -3,18 +3,22 @@
#include "lvgl.h" #include "lvgl.h"
#include <TFT_eSPI.h> #include <TFT_eSPI.h>
#include <HTTPClient.h> #include <HTTPClient.h>
#include "core/data_setup.h"
bool connect_ok = false; bool connect_ok = false;
lv_obj_t * ipEntry; lv_obj_t * ipEntry;
lv_obj_t * portEntry; lv_obj_t * portEntry;
lv_obj_t * label = NULL; lv_obj_t * label = NULL;
void ip_init_inner();
bool verify_ip(){ bool verify_ip(){
HTTPClient client; HTTPClient client;
String url = "http://" + String(global_config.klipperHost) + ":" + String(global_config.klipperPort) + "/printer/info"; String url = "http://" + String(global_config.klipperHost) + ":" + String(global_config.klipperPort) + "/printer/info";
int httpCode; int httpCode;
try { try {
Serial.println(url); Serial.println(url);
client.setTimeout(500);
client.begin(url.c_str()); client.begin(url.c_str());
httpCode = client.GET(); httpCode = client.GET();
return httpCode == 200; return httpCode == 200;
@@ -42,8 +46,8 @@ static void ta_event_cb(lv_event_t * e) {
{ {
strcpy(global_config.klipperHost, lv_textarea_get_text(ipEntry)); strcpy(global_config.klipperHost, lv_textarea_get_text(ipEntry));
global_config.klipperPort = atoi(lv_textarea_get_text(portEntry)); global_config.klipperPort = atoi(lv_textarea_get_text(portEntry));
bool result = verify_ip();
if (result) if (verify_ip())
{ {
global_config.ipConfigured = true; global_config.ipConfigured = true;
WriteGlobalConfig(); WriteGlobalConfig();
@@ -56,9 +60,33 @@ static void ta_event_cb(lv_event_t * e) {
} }
} }
void ip_setup_inner(){ static void reset_btn_event_handler(lv_event_t * e){
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_CLICKED) {
global_config.ipConfigured = false;
ip_init_inner();
}
}
void ip_init_inner(){
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
if (global_config.ipConfigured) {
label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Connecting to Klipper");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
lv_obj_t * resetBtn = lv_btn_create(lv_scr_act());
lv_obj_add_event_cb(resetBtn, reset_btn_event_handler, LV_EVENT_ALL, NULL);
lv_obj_align(resetBtn, LV_ALIGN_CENTER, 0, 40);
lv_obj_t * btnLabel = lv_label_create(resetBtn);
lv_label_set_text(btnLabel, "Reset");
lv_obj_center(btnLabel);
return;
}
lv_obj_t * keyboard = lv_keyboard_create(lv_scr_act()); lv_obj_t * keyboard = lv_keyboard_create(lv_scr_act());
label = lv_label_create(lv_scr_act()); label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Enter Klipper IP and Port"); lv_label_set_text(label, "Enter Klipper IP and Port");
@@ -84,18 +112,37 @@ void ip_setup_inner(){
lv_keyboard_set_textarea(keyboard, ipEntry); lv_keyboard_set_textarea(keyboard, ipEntry);
} }
void ip_setup(){ long last_data_update_ip = -10000;
const long data_update_interval_ip = 10000;
int retry_count = 0;
void ip_init(){
connect_ok = false; connect_ok = false;
retry_count = 0;
if (global_config.ipConfigured && verify_ip()){ ip_init_inner();
return;
}
ip_setup_inner();
while (!connect_ok) while (!connect_ok)
{ {
lv_timer_handler(); lv_timer_handler();
lv_task_handler(); lv_task_handler();
if (!connect_ok && global_config.ipConfigured && (millis() - last_data_update_ip) > data_update_interval_ip){
connect_ok = verify_ip();
last_data_update_ip = millis();
retry_count++;
String retry_count_text = "Connecting to Klipper (Try " + String(retry_count + 1) + ")";
lv_label_set_text(label, retry_count_text.c_str());
}
}
}
void ip_ok(){
if (klipper_request_consecutive_fail_count > 5){
freeze_request_thread();
ip_init();
unfreeze_request_thread();
klipper_request_consecutive_fail_count = 0;
lv_msg_send(DATA_PRINTER_STATE, &printer);
} }
} }

View File

@@ -1 +1,2 @@
void ip_setup(); void ip_init();
void ip_ok();

View File

@@ -71,6 +71,10 @@ static void btn_click_settings(lv_event_t * e){
nav_buttons_setup(3); nav_buttons_setup(3);
} }
static void btn_click_macros(lv_event_t * e){
nav_buttons_setup(4);
}
void nav_buttons_setup(unsigned char active_panel){ void nav_buttons_setup(unsigned char active_panel){
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
lv_obj_clear_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE); lv_obj_clear_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE);
@@ -140,14 +144,14 @@ void nav_buttons_setup(unsigned char active_panel){
lv_obj_set_size(btn, button_width, button_height); lv_obj_set_size(btn, button_width, button_height);
lv_obj_align(btn, LV_ALIGN_TOP_LEFT, 0, button_height * 3); lv_obj_align(btn, LV_ALIGN_TOP_LEFT, 0, button_height * 3);
lv_obj_add_style(btn, &nav_button_style, 0); lv_obj_add_style(btn, &nav_button_style, 0);
lv_obj_add_event_cb(btn, btn_click_settings, LV_EVENT_CLICKED, NULL); lv_obj_add_event_cb(btn, btn_click_macros, LV_EVENT_CLICKED, NULL);
label = lv_label_create(btn); label = lv_label_create(btn);
lv_label_set_text(label, LV_SYMBOL_SETTINGS); lv_label_set_text(label, LV_SYMBOL_GPS);
lv_obj_align(label, LV_ALIGN_CENTER, 0, -1 * icon_text_spacing); lv_obj_align(label, LV_ALIGN_CENTER, 0, -1 * icon_text_spacing);
label = lv_label_create(btn); label = lv_label_create(btn);
lv_label_set_text(label, "Screen"); lv_label_set_text(label, "Macro");
lv_obj_align(label, LV_ALIGN_CENTER, 0, icon_text_spacing); lv_obj_align(label, LV_ALIGN_CENTER, 0, icon_text_spacing);
lv_obj_add_style(label, &nav_button_text_style, 0); lv_obj_add_style(label, &nav_button_text_style, 0);
@@ -171,6 +175,9 @@ void nav_buttons_setup(unsigned char active_panel){
case 3: case 3:
settings_panel_init(panel); settings_panel_init(panel);
break; break;
case 4:
macros_panel_init(panel);
break;
} }
} }

View File

@@ -0,0 +1,81 @@
#include "lvgl.h"
#include "panel.h"
#include "../nav_buttons.h"
#include "../../core/data_setup.h"
#include "../../core/macros_query.h"
#include <HardwareSerial.h>
int y_offset_macros = 40;
const int y_element_size = 50;
const int y_seperator_size = 1;
const int y_seperator_x_padding = 50;
const int panel_width = TFT_HEIGHT - 40;
const int y_element_x_padding = 30;
const static lv_point_t line_points[] = { {0, 0}, {panel_width - y_seperator_x_padding, 0} };
static void btn_press(lv_event_t * e){
lv_obj_t * btn = lv_event_get_target(e);
const char* macro = (const char*)lv_event_get_user_data(e);
Serial.printf("Macro: %s\n", macro);
send_gcode(false, macro);
}
static void btn_goto_settings(lv_event_t * e){
nav_buttons_setup(3);
}
void create_macro_widget(const char* macro, lv_obj_t* root_panel){
lv_obj_t * panel = lv_obj_create(root_panel);
lv_obj_set_style_border_width(panel, 0, 0);
lv_obj_set_style_bg_opa(panel, LV_OPA_TRANSP, 0);
lv_obj_set_style_pad_all(panel, 0, 0);
lv_obj_align(panel, LV_ALIGN_TOP_MID, 0, y_offset_macros);
lv_obj_set_size(panel, panel_width - y_element_x_padding, y_element_size);
lv_obj_t * line = lv_line_create(panel);
lv_line_set_points(line, line_points, 2);
lv_obj_set_style_line_width(line, y_seperator_size, 0);
lv_obj_set_style_line_color(line, lv_color_hex(0xAAAAAA), 0);
lv_obj_align(line, LV_ALIGN_BOTTOM_MID, 0, 0);
lv_obj_t * label = lv_label_create(panel);
lv_label_set_text(label, macro);
lv_obj_align(label, LV_ALIGN_LEFT_MID, 0, 0);
lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_width(label, (TFT_HEIGHT - 40) * 0.75f);
lv_obj_t * btn = lv_btn_create(panel);
lv_obj_align(btn, LV_ALIGN_RIGHT_MID, 0, 0);
lv_obj_add_event_cb(btn, btn_press, LV_EVENT_CLICKED, (void*)macro);
label = lv_label_create(btn);
lv_label_set_text(label, "Run");
lv_obj_center(label);
y_offset_macros += y_element_size;
}
void macros_panel_init(lv_obj_t* panel) {
y_offset_macros = 40;
lv_obj_t * btn = lv_btn_create(panel);
lv_obj_add_event_cb(btn, btn_goto_settings, LV_EVENT_CLICKED, NULL);
lv_obj_set_size(btn, TFT_HEIGHT - 40 - 20, 30);
lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, 5);
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text(label, LV_SYMBOL_SETTINGS " Screen Settings");
lv_obj_center(label);
MACROSQUERY query = macros_query();
if (query.count == 0){
label = lv_label_create(panel);
lv_label_set_text(label, "No macros found.\nMacros with the description\n\"CYD_SCREEN_MACRO\"\nwill show up here.");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
return;
}
for (int i = 0; i < query.count; i++){
create_macro_widget(query.macros[i], panel);
}
}

View File

@@ -7,3 +7,4 @@ void temp_panel_init(lv_obj_t* panel);
void print_panel_init(lv_obj_t* panel); void print_panel_init(lv_obj_t* panel);
void move_panel_init(lv_obj_t* panel); void move_panel_init(lv_obj_t* panel);
void progress_panel_init(lv_obj_t* panel); void progress_panel_init(lv_obj_t* panel);
void macros_panel_init(lv_obj_t* panel);

View File

@@ -12,8 +12,27 @@ static void btn_print_file(lv_event_t * e){
lv_obj_t * panel = (lv_obj_t*)lv_event_get_user_data(e); lv_obj_t * panel = (lv_obj_t*)lv_event_get_user_data(e);
lv_obj_del(panel); lv_obj_del(panel);
char* buff = (char*)malloc(128 + strlen(selected_file->name)); char* buff = (char*)malloc(128 + (strlen(selected_file->name) * 3));
sprintf(buff, "http://%s:%d/printer/print/start?filename=%s", global_config.klipperHost, global_config.klipperPort, selected_file->name); sprintf(buff, "http://%s:%d/printer/print/start?filename=", global_config.klipperHost, global_config.klipperPort);
char* ptr = buff + strlen(buff);
int filename_length = strlen(selected_file->name);
for (int i = 0; i < filename_length; i++){
char c = selected_file->name[i];
if (c == ' '){
*ptr = '%';
ptr++;
*ptr = '2';
ptr++;
*ptr = '0';
} else {
*ptr = c;
}
ptr++;
}
*ptr = 0;
HTTPClient client; HTTPClient client;
client.begin(buff); client.begin(buff);
int httpCode = client.POST(""); int httpCode = client.POST("");
@@ -76,13 +95,20 @@ void print_panel_init(lv_obj_t* panel){
lv_obj_set_size(list, panel_width_margin, panel_height_margin); lv_obj_set_size(list, panel_width_margin, panel_height_margin);
lv_obj_align(list, LV_ALIGN_CENTER, 0, 0); lv_obj_align(list, LV_ALIGN_CENTER, 0, 0);
FILESYSTEM_FILE* files = get_files(); FILESYSTEM_FILE* files = get_files(25);
int count = 0; int count = 0;
while (files->name != NULL && count <= 20){ while (files != NULL && files->name != NULL && count <= 20){
lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_FILE, files->name); lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_FILE, files->name);
lv_obj_add_event_cb(btn, btn_print_file_verify, LV_EVENT_CLICKED, (void*)files); lv_obj_add_event_cb(btn, btn_print_file_verify, LV_EVENT_CLICKED, (void*)files);
files += 1; files += 1;
count++; count++;
} }
if (count <= 0){
lv_obj_del(list);
lv_obj_t * label = lv_label_create(panel);
lv_label_set_text(label, "Failed to read files.");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
}
} }

View File

@@ -1,25 +1,70 @@
#include "lvgl.h" #include "lvgl.h"
#include "panel.h"
#include "../../core/data_setup.h" #include "../../core/data_setup.h"
#include "../../conf/global_config.h"
#include <HardwareSerial.h> #include <HardwareSerial.h>
// False: Hotend, True: Bed enum temp_target{
static bool hotend_or_bed = true; TARGET_HOTEND,
TARGET_BED,
TARGET_HOTEND_CONFIG_1,
TARGET_HOTEND_CONFIG_2,
TARGET_HOTEND_CONFIG_3,
TARGET_BED_CONFIG_1,
TARGET_BED_CONFIG_2,
TARGET_BED_CONFIG_3,
};
static temp_target keyboard_target;
static char hotend_buff[40]; static char hotend_buff[40];
static char bed_buff[40]; static char bed_buff[40];
static bool edit_mode = false;
lv_obj_t* root_panel;
static void update_printer_data_hotend_temp(lv_event_t * e){ static void update_printer_data_hotend_temp(lv_event_t * e){
lv_obj_t * label = lv_event_get_target(e); lv_obj_t * label = lv_event_get_target(e);
sprintf(hotend_buff, "Hotend: %.0f C\nTarget: %.0f C", printer.extruder_temp, printer.extruder_target_temp); sprintf(hotend_buff, "Hotend: %.0f C (Target: %.0f C)", printer.extruder_temp, printer.extruder_target_temp);
lv_label_set_text(label, hotend_buff); lv_label_set_text(label, hotend_buff);
} }
static void update_printer_data_bed_temp(lv_event_t * e){ static void update_printer_data_bed_temp(lv_event_t * e){
lv_obj_t * label = lv_event_get_target(e); lv_obj_t * label = lv_event_get_target(e);
sprintf(bed_buff, "Bed: %.0f C\nTarget: %.0f C", printer.bed_temp, printer.bed_target_temp); sprintf(bed_buff, "Bed: %.0f C (Target: %.0f C)", printer.bed_temp, printer.bed_target_temp);
lv_label_set_text(label, bed_buff); lv_label_set_text(label, bed_buff);
} }
static short get_temp_preset(int target){
switch (target){
case TARGET_HOTEND_CONFIG_1:
return global_config.hotend_presets[0];
case TARGET_HOTEND_CONFIG_2:
return global_config.hotend_presets[1];
case TARGET_HOTEND_CONFIG_3:
return global_config.hotend_presets[2];
case TARGET_BED_CONFIG_1:
return global_config.bed_presets[0];
case TARGET_BED_CONFIG_2:
return global_config.bed_presets[1];
case TARGET_BED_CONFIG_3:
return global_config.bed_presets[2];
default:
return -1;
}
}
static void update_temp_preset_label(lv_event_t * e){
lv_obj_t * label = lv_event_get_target(e);
int target = static_cast<int>(reinterpret_cast<intptr_t>(lv_event_get_user_data(e)));
short value = get_temp_preset(target);
String text_label = String(value) + " C";
lv_label_set_text(label, text_label.c_str());
}
void UpdateConfig(){
WriteGlobalConfig();
lv_msg_send(DATA_PRINTER_TEMP_PRESET, &printer);
}
static void keyboard_callback(lv_event_t * e){ static void keyboard_callback(lv_event_t * e){
lv_event_code_t code = lv_event_get_code(e); lv_event_code_t code = lv_event_get_code(e);
lv_obj_t * ta = lv_event_get_target(e); lv_obj_t * ta = lv_event_get_target(e);
@@ -33,17 +78,43 @@ static void keyboard_callback(lv_event_t * e){
return; return;
} }
Serial.printf("%d %s %d\n", hotend_or_bed, text, temp);
char gcode[64]; char gcode[64];
const char* space = "%20"; const char* space = "%20";
if (hotend_or_bed){ switch (keyboard_target){
sprintf(gcode, "M140%sS%d", space, temp); case TARGET_HOTEND:
} else {
sprintf(gcode, "M104%sS%d", space, temp); sprintf(gcode, "M104%sS%d", space, temp);
}
send_gcode(true, gcode); send_gcode(true, gcode);
break;
case TARGET_BED:
sprintf(gcode, "M140%sS%d", space, temp);
send_gcode(true, gcode);
break;
case TARGET_HOTEND_CONFIG_1:
global_config.hotend_presets[0] = temp;
UpdateConfig();
break;
case TARGET_HOTEND_CONFIG_2:
global_config.hotend_presets[1] = temp;
UpdateConfig();
break;
case TARGET_HOTEND_CONFIG_3:
global_config.hotend_presets[2] = temp;
UpdateConfig();
break;
case TARGET_BED_CONFIG_1:
global_config.bed_presets[0] = temp;
UpdateConfig();
break;
case TARGET_BED_CONFIG_2:
global_config.bed_presets[1] = temp;
UpdateConfig();
break;
case TARGET_BED_CONFIG_3:
global_config.bed_presets[2] = temp;
UpdateConfig();
break;
}
} }
if(code == LV_EVENT_DEFOCUSED || code == LV_EVENT_CANCEL || code == LV_EVENT_READY) { if(code == LV_EVENT_DEFOCUSED || code == LV_EVENT_CANCEL || code == LV_EVENT_READY) {
@@ -54,14 +125,14 @@ static void keyboard_callback(lv_event_t * e){
} }
static void show_keyboard(lv_event_t * e){ static void show_keyboard(lv_event_t * e){
lv_obj_t * panel = (lv_obj_t *)lv_event_get_user_data(e); lv_obj_t * keyboard = lv_keyboard_create(root_panel);
lv_obj_t * keyboard = lv_keyboard_create(panel); lv_obj_t * ta = lv_textarea_create(root_panel);
lv_obj_t * ta = lv_textarea_create(panel); lv_obj_set_size(ta, TFT_HEIGHT - 40, 120);
lv_obj_set_size(ta, 100, 30); lv_obj_align(ta, LV_ALIGN_TOP_MID, 0, 0);
lv_obj_align(ta, LV_ALIGN_TOP_MID, 0, 40);
lv_textarea_set_max_length(ta, 3); lv_textarea_set_max_length(ta, 3);
lv_textarea_set_one_line(ta, true); //lv_textarea_set_one_line(ta, true);
lv_textarea_set_text(ta, ""); lv_textarea_set_text(ta, "");
lv_textarea_set_align(ta, LV_TEXT_ALIGN_CENTER);
lv_obj_add_event_cb(ta, keyboard_callback, LV_EVENT_ALL, keyboard); lv_obj_add_event_cb(ta, keyboard_callback, LV_EVENT_ALL, keyboard);
lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_NUMBER); lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_NUMBER);
@@ -69,12 +140,12 @@ static void show_keyboard(lv_event_t * e){
} }
static void show_keyboard_with_hotend(lv_event_t * e){ static void show_keyboard_with_hotend(lv_event_t * e){
hotend_or_bed = false; keyboard_target = TARGET_HOTEND;
show_keyboard(e); show_keyboard(e);
} }
static void show_keyboard_with_bed(lv_event_t * e){ static void show_keyboard_with_bed(lv_event_t * e){
hotend_or_bed = true; keyboard_target = TARGET_BED;
show_keyboard(e); show_keyboard(e);
} }
@@ -96,6 +167,32 @@ static void btn_extrude(lv_event_t * e){
send_gcode(true, "G1%20E25%20F300"); send_gcode(true, "G1%20E25%20F300");
} }
static void set_temp_via_preset(lv_event_t * e){
int target = static_cast<int>(reinterpret_cast<intptr_t>(lv_event_get_user_data(e)));
int value = get_temp_preset(target);
if (edit_mode) {
keyboard_target = (temp_target)target;
show_keyboard(e);
return;
}
char gcode[64];
const char* space = "%20";
if (target <= TARGET_HOTEND_CONFIG_3)
sprintf(gcode, "M104%sS%d", space, value);
else
sprintf(gcode, "M140%sS%d", space, value);
send_gcode(true, gcode);
}
static void btn_toggleable_edit(lv_event_t * e){
lv_obj_t * btn = lv_event_get_target(e);
auto state = lv_obj_get_state(btn);
edit_mode = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
}
static void btn_retract(lv_event_t * e){ static void btn_retract(lv_event_t * e){
if (printer.state == PRINTER_STATE_PRINTING){ if (printer.state == PRINTER_STATE_PRINTING){
return; return;
@@ -106,47 +203,91 @@ static void btn_retract(lv_event_t * e){
} }
void temp_panel_init(lv_obj_t* panel){ void temp_panel_init(lv_obj_t* panel){
root_panel = panel;
edit_mode = false;
const int btn_row_y_one = 30;
const int btn_row_y_two = 100;
auto panel_width = TFT_HEIGHT - 40; auto panel_width = TFT_HEIGHT - 40;
lv_obj_t * label = lv_label_create(panel); lv_obj_t * label = lv_label_create(panel);
lv_label_set_text(label, "Hotend"); lv_label_set_text(label, "???");
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 10, 10); lv_obj_align(label, LV_ALIGN_TOP_LEFT, 10, 10);
lv_obj_add_event_cb(label, update_printer_data_hotend_temp, LV_EVENT_MSG_RECEIVED, NULL); lv_obj_add_event_cb(label, update_printer_data_hotend_temp, LV_EVENT_MSG_RECEIVED, NULL);
lv_msg_subscribe_obj(DATA_PRINTER_DATA, label, NULL); lv_msg_subscribe_obj(DATA_PRINTER_DATA, label, NULL);
label = lv_label_create(panel); label = lv_label_create(panel);
lv_label_set_text(label, "Bed"); lv_label_set_text(label, "???");
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 10, 50); lv_obj_align(label, LV_ALIGN_TOP_LEFT, 10, 80);
lv_obj_add_event_cb(label, update_printer_data_bed_temp, LV_EVENT_MSG_RECEIVED, NULL); lv_obj_add_event_cb(label, update_printer_data_bed_temp, LV_EVENT_MSG_RECEIVED, NULL);
lv_msg_subscribe_obj(DATA_PRINTER_DATA, label, NULL); lv_msg_subscribe_obj(DATA_PRINTER_DATA, label, NULL);
lv_obj_t * btn = lv_btn_create(panel); lv_obj_t * btn = lv_btn_create(panel);
lv_obj_align(btn, LV_ALIGN_TOP_RIGHT, -10, 10); lv_obj_align(btn, LV_ALIGN_TOP_RIGHT, -10, btn_row_y_one);
lv_obj_add_event_cb(btn, show_keyboard_with_hotend, LV_EVENT_CLICKED, panel); lv_obj_add_event_cb(btn, show_keyboard_with_hotend, LV_EVENT_CLICKED, panel);
lv_obj_set_width(btn, panel_width / 4 - 10);
label = lv_label_create(btn); label = lv_label_create(btn);
lv_label_set_text(label, "Set"); lv_label_set_text(label, "Set");
lv_obj_center(label); lv_obj_center(label);
btn = lv_btn_create(panel); btn = lv_btn_create(panel);
lv_obj_align(btn, LV_ALIGN_TOP_RIGHT, -10, 50); lv_obj_align(btn, LV_ALIGN_TOP_RIGHT, -10, btn_row_y_two);
lv_obj_add_event_cb(btn, show_keyboard_with_bed, LV_EVENT_CLICKED, panel); lv_obj_add_event_cb(btn, show_keyboard_with_bed, LV_EVENT_CLICKED, panel);
lv_obj_set_width(btn, panel_width / 4 - 10);
label = lv_label_create(btn); label = lv_label_create(btn);
lv_label_set_text(label, "Set"); lv_label_set_text(label, "Set");
lv_obj_center(label); lv_obj_center(label);
// Presets
for (int i = 0; i < 3; i++){
int x_pos = 10 + (panel_width / 4) * i - (3 * i);
btn = lv_btn_create(panel); btn = lv_btn_create(panel);
lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, 90); lv_obj_align(btn, LV_ALIGN_TOP_LEFT, x_pos, btn_row_y_one);
lv_obj_add_event_cb(btn, set_temp_via_preset, LV_EVENT_CLICKED, reinterpret_cast<void*>(TARGET_HOTEND_CONFIG_1 + i));
lv_obj_set_width(btn, panel_width / 4 - 10);
label = lv_label_create(btn);
lv_label_set_text(label, "???");
lv_obj_center(label);
lv_obj_add_event_cb(label, update_temp_preset_label, LV_EVENT_MSG_RECEIVED, reinterpret_cast<void*>(TARGET_HOTEND_CONFIG_1 + i));
lv_msg_subscribe_obj(DATA_PRINTER_TEMP_PRESET, label, NULL);
btn = lv_btn_create(panel);
lv_obj_align(btn, LV_ALIGN_TOP_LEFT, x_pos, btn_row_y_two);
lv_obj_add_event_cb(btn, set_temp_via_preset, LV_EVENT_CLICKED, reinterpret_cast<void*>(TARGET_BED_CONFIG_1 + i));
lv_obj_set_width(btn, panel_width / 4 - 10);
label = lv_label_create(btn);
lv_label_set_text(label, "???");
lv_obj_center(label);
lv_obj_add_event_cb(label, update_temp_preset_label, LV_EVENT_MSG_RECEIVED, reinterpret_cast<void*>(TARGET_BED_CONFIG_1 + i));
lv_msg_subscribe_obj(DATA_PRINTER_TEMP_PRESET, label, NULL);
}
btn = lv_btn_create(panel);
lv_obj_align(btn, LV_ALIGN_BOTTOM_LEFT, 10, -50);
lv_obj_set_size(btn, panel_width / 2 - 15, 40);
lv_obj_add_event_cb(btn, cooldown_temp, LV_EVENT_CLICKED, panel); lv_obj_add_event_cb(btn, cooldown_temp, LV_EVENT_CLICKED, panel);
label = lv_label_create(btn); label = lv_label_create(btn);
lv_label_set_text(label, "Cooldown"); lv_label_set_text(label, "Cooldown");
lv_obj_center(label); lv_obj_center(label);
btn = lv_btn_create(panel);
lv_obj_align(btn, LV_ALIGN_BOTTOM_RIGHT, -10, -50);
lv_obj_add_event_cb(btn, btn_toggleable_edit, LV_EVENT_CLICKED, NULL);
lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);
lv_obj_set_size(btn, panel_width / 2 - 15, 40);
label = lv_label_create(btn);
lv_label_set_text(label, "Edit Presets");
lv_obj_center(label);
btn = lv_btn_create(panel); btn = lv_btn_create(panel);
lv_obj_align(btn, LV_ALIGN_BOTTOM_LEFT, 10, -5); lv_obj_align(btn, LV_ALIGN_BOTTOM_LEFT, 10, -5);
lv_obj_add_event_cb(btn, btn_extrude, LV_EVENT_CLICKED, NULL); lv_obj_add_event_cb(btn, btn_extrude, LV_EVENT_CLICKED, NULL);
lv_obj_set_size(btn, panel_width / 2 - 15, 30); lv_obj_set_size(btn, panel_width / 2 - 15, 40);
label = lv_label_create(btn); label = lv_label_create(btn);
lv_label_set_text(label, LV_SYMBOL_DOWN " Extrude"); lv_label_set_text(label, LV_SYMBOL_DOWN " Extrude");
@@ -155,11 +296,12 @@ void temp_panel_init(lv_obj_t* panel){
btn = lv_btn_create(panel); btn = lv_btn_create(panel);
lv_obj_align(btn, LV_ALIGN_BOTTOM_RIGHT, -10, -5); lv_obj_align(btn, LV_ALIGN_BOTTOM_RIGHT, -10, -5);
lv_obj_add_event_cb(btn, btn_retract, LV_EVENT_CLICKED, NULL); lv_obj_add_event_cb(btn, btn_retract, LV_EVENT_CLICKED, NULL);
lv_obj_set_size(btn, panel_width / 2 - 15, 30); lv_obj_set_size(btn, panel_width / 2 - 15, 40);
label = lv_label_create(btn); label = lv_label_create(btn);
lv_label_set_text(label, LV_SYMBOL_UP " Retract"); lv_label_set_text(label, LV_SYMBOL_UP " Retract");
lv_obj_center(label); lv_obj_center(label);
lv_msg_send(DATA_PRINTER_DATA, &printer); lv_msg_send(DATA_PRINTER_DATA, &printer);
lv_msg_send(DATA_PRINTER_TEMP_PRESET, &printer);
} }

View File

@@ -77,12 +77,11 @@ static void wifi_btn_event_handler(lv_event_t * e){
void wifi_init_inner(){ void wifi_init_inner(){
WiFi.disconnect(); WiFi.disconnect();
lv_obj_clean(lv_scr_act());
if (global_config.wifiConfigured){ if (global_config.wifiConfigured){
WiFi.begin(global_config.wifiSSID, global_config.wifiPassword); WiFi.begin(global_config.wifiSSID, global_config.wifiPassword);
lv_obj_clean(lv_scr_act());
lv_obj_t * label = lv_label_create(lv_scr_act()); lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Connecting to WiFi"); lv_label_set_text(label, "Connecting to WiFi");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
@@ -98,8 +97,6 @@ void wifi_init_inner(){
return; return;
} }
lv_obj_clean(lv_scr_act());
lv_obj_t * label = lv_label_create(lv_scr_act()); lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Scanning for networks..."); lv_label_set_text(label, "Scanning for networks...");
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
@@ -108,8 +105,6 @@ void wifi_init_inner(){
lv_task_handler(); lv_task_handler();
lv_refr_now(NULL); lv_refr_now(NULL);
int n = WiFi.scanNetworks();
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
lv_obj_t * refreshBtn = lv_btn_create(lv_scr_act()); lv_obj_t * refreshBtn = lv_btn_create(lv_scr_act());
@@ -128,25 +123,50 @@ void wifi_init_inner(){
lv_obj_align(list, LV_ALIGN_TOP_LEFT, 10, 40); lv_obj_align(list, LV_ALIGN_TOP_LEFT, 10, 40);
lv_obj_set_size(list, TFT_HEIGHT - 20, TFT_WIDTH - 40 - 5); lv_obj_set_size(list, TFT_HEIGHT - 20, TFT_WIDTH - 40 - 5);
for (int i = 0; i < n; ++i) { int n = WiFi.scanNetworks();
const char* ssid = WiFi.SSID(i).c_str();
int len = strlen(ssid);
if (len == 0) for (int i = 0; i < n; ++i) {
String ssid = WiFi.SSID(i);
char* ssid_copy = (char*)malloc(ssid.length() + 1);
int j = 0;
for (; j < ssid.length(); ++j){
if (ssid[j] == '\0')
continue; continue;
const char* ssid_copy = (const char*)malloc(len + 1); ssid_copy[j] = ssid[j];
strcpy((char*)ssid_copy, ssid); }
ssid_copy[j] = '\0';
lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_WIFI, ssid_copy); lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_WIFI, ssid_copy);
lv_obj_add_event_cb(btn, wifi_btn_event_handler, LV_EVENT_ALL, (void*)ssid_copy); lv_obj_add_event_cb(btn, wifi_btn_event_handler, LV_EVENT_ALL, (void*)ssid_copy);
} }
} }
const char* errs[] = {
"Idle",
"No SSID Available",
"Scan Completed",
"Connected",
"Connection Failed",
"Connection Lost",
"Disconnected"
};
const int print_freq = 1000;
int print_timer = 0;
void wifi_init(){ void wifi_init(){
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
wifi_init_inner(); wifi_init_inner();
while (!global_config.wifiConfigured || WiFi.status() != WL_CONNECTED){ while (!global_config.wifiConfigured || WiFi.status() != WL_CONNECTED){
if (millis() - print_timer > print_freq){
print_timer = millis();
Serial.printf("WiFi Status: %s\n", errs[WiFi.status()]);
}
lv_timer_handler(); lv_timer_handler();
lv_task_handler(); lv_task_handler();
} }

View File

@@ -2,7 +2,7 @@
[![Donations](https://img.shields.io/badge/Support%20on-Ko--Fi-red)](https://ko-fi.com/suchmememanyskill) [![Donations](https://img.shields.io/badge/Support%20on-Ko--Fi-red)](https://ko-fi.com/suchmememanyskill)
# CYD-Klipper # CYD-Klipper
An implementation of a Klipper status display on an ESP32 + screen. Uses Moonraker to fetch data. An implementation of a wireless Klipper status display on an ESP32 + screen. Uses Moonraker to fetch data.
A simple and cheap solution to use a dedicated screen with Klipper, a 3d printing Firmware. A simple and cheap solution to use a dedicated screen with Klipper, a 3d printing Firmware.
@@ -19,6 +19,7 @@ A ESP32-2432S028R is required to run this project. You can find out where to buy
- Move the printer - Move the printer
- Manage temperature - Manage temperature
- Extrude/Retract filament - Extrude/Retract filament
- Execute predefined gcode macros
### Install ### Install

View File

@@ -22,6 +22,7 @@
<p>An implementation of a Klipper status display on an ESP32 + screen.<br>Uses Moonraker to fetch data.</p> <p>An implementation of a Klipper status display on an ESP32 + screen.<br>Uses Moonraker to fetch data.</p>
<img alt="GitHub release (with filter)" src="https://img.shields.io/github/v/release/suchmememanyskill/CYD-Klipper"> <img alt="GitHub release (with filter)" src="https://img.shields.io/github/v/release/suchmememanyskill/CYD-Klipper">
<a href="https://github.com/suchmememanyskill/CYD-Klipper"><img alt="GitHub repo" src="https://img.shields.io/badge/Source-Github-blue.svg"></a> <a href="https://github.com/suchmememanyskill/CYD-Klipper"><img alt="GitHub repo" src="https://img.shields.io/badge/Source-Github-blue.svg"></a>
<a href="https://ko-fi.com/suchmememanyskill"><img alt="Donate KoFi" src="https://img.shields.io/badge/Support%2FDonate%20On-Ko%20Fi-red"></a>
<section class="install"> <section class="install">
<h3>Install</h3> <h3>Install</h3>
<p>Note: You may need to hold the 'BOOT' button on the device while pressing install</p> <p>Note: You may need to hold the 'BOOT' button on the device while pressing install</p>