Merge branch '0.4.0-dev' into linux

This commit is contained in:
Thomas Langewouters 2021-03-01 21:46:10 +01:00 committed by GitHub
commit 6681b2765b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 720 additions and 304 deletions

View File

@ -5,9 +5,9 @@
#if 1 /*Set it to "1" to enable content*/ #if 1 /*Set it to "1" to enable content*/
#ifndef LV_CONF_H #ifndef LV_CONF_H
#define LV_CONF_H #define LV_CONF_H
/* clang-format off */ /* clang-format off */
#include <stdint.h> #include <stdint.h>
@ -183,14 +183,14 @@ typedef void* lv_group_user_data_t;
typedef void* lv_fs_drv_user_data_t; typedef void* lv_fs_drv_user_data_t;
/*File system interface*/ /*File system interface*/
#define LV_USE_FS_IF 0 #define LV_USE_FS_IF 1
#if LV_USE_FS_IF #if LV_USE_FS_IF
# define LV_FS_IF_FATFS '\0' # define LV_FS_IF_FATFS '\0'
#if defined(ARDUINO_ARCH_ESP32) // || defined(ARDUINO_ARCH_ESP8266) #if defined(STM32F4xx) // || defined(ARDUINO_ARCH_ESP8266)
# define LV_FS_IF_PC 'S' # define LV_FS_IF_PC '\0'
# define LV_FS_IF_SPIFFS '\0' // internal esp Flash # define LV_FS_IF_SPIFFS '\0' // internal esp Flash
#else #else
# define LV_FS_IF_PC '\0' # define LV_FS_IF_PC 'S'
# define LV_FS_IF_SPIFFS '\0' // no internal esp Flash # define LV_FS_IF_SPIFFS '\0' // no internal esp Flash
#endif #endif
#endif /*LV_USE_FS_IF*/ #endif /*LV_USE_FS_IF*/

View File

@ -8,58 +8,62 @@
*********************/ *********************/
#include "lv_fs_if.h" #include "lv_fs_if.h"
#if LV_USE_FS_IF #if LV_USE_FS_IF
#if LV_FS_IF_PC != '\0' #if LV_FS_IF_PC != '\0'
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <dirent.h> #include <unistd.h>
#include <unistd.h> #if !defined(ARDUINO_ARCH_ESP8266) && !defined(STM32F4xx)
#ifdef WIN32 #include <dirent.h>
#include <windows.h> #endif
#endif #ifdef WIN32
#include <windows.h>
#endif
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/
#ifndef LV_FS_PC_PATH #ifndef LV_FS_PC_PATH
#ifndef WIN32 #ifndef WIN32
#define LV_FS_PC_PATH "/fs" /*Projet root*/ #define LV_FS_PC_PATH "/fs" /*Projet root*/
#else #else
#define LV_FS_PC_PATH ".\\" /*Projet root*/ #define LV_FS_PC_PATH ".\\" /*Projet root*/
#endif #endif
#endif /*LV_FS_PATH*/ #endif /*LV_FS_PATH*/
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
/* Create a type to store the required data about your file. */ /* Create a type to store the required data about your file. */
typedef FILE * file_t; typedef FILE* file_t;
/*Similarly to `file_t` create a type for directory reading too */ /*Similarly to `file_t` create a type for directory reading too */
#ifndef WIN32 #if defined(WIN32)
typedef DIR * dir_t;
#else
typedef HANDLE dir_t; typedef HANDLE dir_t;
#endif #elif defined(ARDUINO_ARCH_ESP8266) || defined(STM32F4xx)
typedef FILE* dir_t;
#else
typedef DIR* dir_t;
#endif
/********************** /**********************
* STATIC PROTOTYPES * STATIC PROTOTYPES
**********************/ **********************/
static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode); static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p); static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p);
static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br); static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br);
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw); static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uint32_t btw, uint32_t* bw);
static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos); static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos);
static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p); static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p);
static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p); static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p);
static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path); static lv_fs_res_t fs_remove(lv_fs_drv_t* drv, const char* path);
static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p); static lv_fs_res_t fs_trunc(lv_fs_drv_t* drv, void* file_p);
static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * newname); static lv_fs_res_t fs_rename(lv_fs_drv_t* drv, const char* oldname, const char* newname);
static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p); static lv_fs_res_t fs_free(lv_fs_drv_t* drv, uint32_t* total_p, uint32_t* free_p);
static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * path); static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path);
static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn); static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn);
static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p); static lv_fs_res_t fs_dir_close(lv_fs_drv_t* drv, void* dir_p);
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
@ -121,12 +125,12 @@ void lv_fs_if_pc_init(void)
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) static lv_fs_res_t fs_open(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
errno = 0; errno = 0;
const char * flags = ""; const char* flags = "";
if(mode == LV_FS_MODE_WR) if(mode == LV_FS_MODE_WR)
flags = "wb"; flags = "wb";
@ -135,16 +139,16 @@ static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path,
else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD))
flags = "rb+"; flags = "rb+";
/*Make the path relative to the current directory (the projects root folder)*/ /*Make the path relative to the current directory (the projects root folder)*/
#ifndef WIN32 #ifndef WIN32
char buf[256]; char buf[256];
sprintf(buf, LV_FS_PC_PATH "/%s", path); sprintf(buf, LV_FS_PC_PATH "/%s", path);
printf("%s\n", buf); printf("%s\n", buf);
#else #else
char buf[256]; char buf[256];
sprintf(buf, LV_FS_PC_PATH "\\%s", path); sprintf(buf, LV_FS_PC_PATH "\\%s", path);
#endif #endif
file_t f = fopen(buf, flags); file_t f = fopen(buf, flags);
if(f == NULL) { if(f == NULL) {
@ -156,8 +160,8 @@ static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path,
/* 'file_p' is pointer to a file descriptor and /* 'file_p' is pointer to a file descriptor and
* we need to store our file descriptor here*/ * we need to store our file descriptor here*/
file_t * fp = file_p; /*Just avoid the confusing casings*/ file_t* fp = file_p; /*Just avoid the confusing casings*/
*fp = f; *fp = f;
return LV_FS_RES_OK; return LV_FS_RES_OK;
} }
@ -169,10 +173,10 @@ static lv_fs_res_t fs_open(lv_fs_drv_t * drv, void * file_p, const char * path,
* @return LV_FS_RES_OK: no error, the file is read * @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum * any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p) static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/ file_t* fp = file_p; /*Just avoid the confusing casings*/
fclose(*fp); fclose(*fp);
return LV_FS_RES_OK; return LV_FS_RES_OK;
} }
@ -187,11 +191,11 @@ static lv_fs_res_t fs_close(lv_fs_drv_t * drv, void * file_p)
* @return LV_FS_RES_OK: no error, the file is read * @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum * any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p, void* buf, uint32_t btr, uint32_t* br)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/ file_t* fp = file_p; /*Just avoid the confusing casings*/
*br = fread(buf, 1, btr, *fp); *br = fread(buf, 1, btr, *fp);
return LV_FS_RES_OK; return LV_FS_RES_OK;
} }
@ -204,11 +208,11 @@ static lv_fs_res_t fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_
* @param br the number of real written bytes (Bytes Written). NULL if unused. * @param br the number of real written bytes (Bytes Written). NULL if unused.
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw) static lv_fs_res_t fs_write(lv_fs_drv_t* drv, void* file_p, const void* buf, uint32_t btw, uint32_t* bw)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/ file_t* fp = file_p; /*Just avoid the confusing casings*/
*bw = fwrite(buf, 1, btw, *fp); *bw = fwrite(buf, 1, btw, *fp);
return LV_FS_RES_OK; return LV_FS_RES_OK;
} }
@ -220,10 +224,10 @@ static lv_fs_res_t fs_write(lv_fs_drv_t * drv, void * file_p, const void * buf,
* @return LV_FS_RES_OK: no error, the file is read * @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum * any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos) static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p, uint32_t pos)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/ file_t* fp = file_p; /*Just avoid the confusing casings*/
fseek(*fp, pos, SEEK_SET); fseek(*fp, pos, SEEK_SET);
return LV_FS_RES_OK; return LV_FS_RES_OK;
} }
@ -235,10 +239,10 @@ static lv_fs_res_t fs_seek(lv_fs_drv_t * drv, void * file_p, uint32_t pos)
* @param size pointer to a variable to store the size * @param size pointer to a variable to store the size
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p) static lv_fs_res_t fs_size(lv_fs_drv_t* drv, void* file_p, uint32_t* size_p)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/ file_t* fp = file_p; /*Just avoid the confusing casings*/
uint32_t cur = ftell(*fp); uint32_t cur = ftell(*fp);
@ -258,11 +262,11 @@ static lv_fs_res_t fs_size(lv_fs_drv_t * drv, void * file_p, uint32_t * size_p)
* @return LV_FS_RES_OK: no error, the file is read * @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum * any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/ file_t* fp = file_p; /*Just avoid the confusing casings*/
*pos_p = ftell(*fp); *pos_p = ftell(*fp);
return LV_FS_RES_OK; return LV_FS_RES_OK;
} }
@ -272,7 +276,7 @@ static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
* @param path path of the file to delete * @param path path of the file to delete
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path) static lv_fs_res_t fs_remove(lv_fs_drv_t* drv, const char* path)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
lv_fs_res_t res = LV_FS_RES_NOT_IMP; lv_fs_res_t res = LV_FS_RES_NOT_IMP;
@ -289,10 +293,10 @@ static lv_fs_res_t fs_remove(lv_fs_drv_t * drv, const char * path)
* @return LV_FS_RES_OK: no error, the file is read * @return LV_FS_RES_OK: no error, the file is read
* any error from lv_fs_res_t enum * any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p) static lv_fs_res_t fs_trunc(lv_fs_drv_t* drv, void* file_p)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
file_t * fp = file_p; /*Just avoid the confusing casings*/ file_t* fp = file_p; /*Just avoid the confusing casings*/
fflush(*fp); /*If not syncronized fclose can write the truncated part*/ fflush(*fp); /*If not syncronized fclose can write the truncated part*/
uint32_t p = ftell(*fp); uint32_t p = ftell(*fp);
@ -307,7 +311,7 @@ static lv_fs_res_t fs_trunc(lv_fs_drv_t * drv, void * file_p)
* @param newname path with the new name * @param newname path with the new name
* @return LV_FS_RES_OK or any error from 'fs_res_t' * @return LV_FS_RES_OK or any error from 'fs_res_t'
*/ */
static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char * newname) static lv_fs_res_t fs_rename(lv_fs_drv_t* drv, const char* oldname, const char* newname)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
static char new[512]; static char new[512];
@ -316,12 +320,14 @@ static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char
sprintf(old, LV_FS_PC_PATH "/%s", oldname); sprintf(old, LV_FS_PC_PATH "/%s", oldname);
sprintf(new, LV_FS_PC_PATH "/%s", newname); sprintf(new, LV_FS_PC_PATH "/%s", newname);
int r = rename(old, new); return LV_FS_RES_UNKNOWN;
if(r == 0) // int r = rename(old, new);
return LV_FS_RES_OK;
else // if(r == 0)
return LV_FS_RES_UNKNOWN; // return LV_FS_RES_OK;
// else
// return LV_FS_RES_UNKNOWN;
} }
/** /**
@ -332,7 +338,7 @@ static lv_fs_res_t fs_rename(lv_fs_drv_t * drv, const char * oldname, const char
* @param free_p pointer to store the free size [kB] * @param free_p pointer to store the free size [kB]
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * free_p) static lv_fs_res_t fs_free(lv_fs_drv_t* drv, uint32_t* total_p, uint32_t* free_p)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
lv_fs_res_t res = LV_FS_RES_NOT_IMP; lv_fs_res_t res = LV_FS_RES_NOT_IMP;
@ -342,9 +348,9 @@ static lv_fs_res_t fs_free(lv_fs_drv_t * drv, uint32_t * total_p, uint32_t * fre
return res; return res;
} }
#ifdef WIN32 #ifdef WIN32
static char next_fn[256]; static char next_fn[256];
#endif #endif
/** /**
* Initialize a 'fs_read_dir_t' variable for directory reading * Initialize a 'fs_read_dir_t' variable for directory reading
@ -353,11 +359,14 @@ static char next_fn[256];
* @param path path to a directory * @param path path to a directory
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * path) static lv_fs_res_t fs_dir_open(lv_fs_drv_t* drv, void* dir_p, const char* path)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
dir_t d; dir_t d;
#ifndef WIN32 #if defined(ARDUINO_ARCH_ESP8266) || defined(STM32F4xx)
return LV_FS_RES_UNKNOWN;
#elif !defined(WIN32)
/*Make the path relative to the current directory (the projects root folder)*/ /*Make the path relative to the current directory (the projects root folder)*/
char buf[256]; char buf[256];
sprintf(buf, LV_FS_PC_PATH "/%s", path); sprintf(buf, LV_FS_PC_PATH "/%s", path);
@ -366,10 +375,10 @@ static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * pat
} else { } else {
/* 'dir_p' is pointer to a file descriptor and /* 'dir_p' is pointer to a file descriptor and
* we need to store our file descriptor here*/ * we need to store our file descriptor here*/
dir_t * dp = dir_p; /*Just avoid the confusing casings*/ dir_t* dp = dir_p; /*Just avoid the confusing casings*/
*dp = d; *dp = d;
} }
#else #else
d = INVALID_HANDLE_VALUE; d = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA fdata; WIN32_FIND_DATA fdata;
@ -393,10 +402,10 @@ static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * pat
} }
} while(FindNextFileA(d, &fdata)); } while(FindNextFileA(d, &fdata));
dir_t * dp = dir_p; /*Just avoid the confusing casings*/ dir_t* dp = dir_p; /*Just avoid the confusing casings*/
*dp = d; *dp = d;
#endif #endif
return LV_FS_RES_OK; return LV_FS_RES_OK;
} }
@ -409,17 +418,18 @@ static lv_fs_res_t fs_dir_open(lv_fs_drv_t * drv, void * dir_p, const char * pat
* @param fn pointer to a buffer to store the filename * @param fn pointer to a buffer to store the filename
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn) static lv_fs_res_t fs_dir_read(lv_fs_drv_t* drv, void* dir_p, char* fn)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
dir_t * dp = dir_p; /*Just avoid the confusing casings*/ dir_t* dp = dir_p; /*Just avoid the confusing casings*/
#ifndef WIN32 #ifdef ARDUINO_ARCH_ESP32
struct dirent * entry; struct dirent* entry;
do { do {
entry = readdir(*dp); entry = readdir(*dp);
if(entry) { if(entry) {
if(entry->d_type == DT_DIR) if(entry->d_type == DT_DIR)
sprintf(fn, "/%s", entry->d_name); sprintf(fn, "/%s", entry->d_name);
else else
@ -428,7 +438,9 @@ static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn)
strcpy(fn, ""); strcpy(fn, "");
} }
} while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0); } while(strcmp(fn, "/.") == 0 || strcmp(fn, "/..") == 0);
#else #endif
#ifdef WIN32
strcpy(fn, next_fn); strcpy(fn, next_fn);
strcpy(next_fn, ""); strcpy(next_fn, "");
@ -449,7 +461,7 @@ static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn)
} }
} while(FindNextFile(*dp, &fdata)); } while(FindNextFile(*dp, &fdata));
#endif #endif
return LV_FS_RES_OK; return LV_FS_RES_OK;
} }
@ -459,18 +471,21 @@ static lv_fs_res_t fs_dir_read(lv_fs_drv_t * drv, void * dir_p, char * fn)
* @param dir_p pointer to an initialized 'fs_read_dir_t' variable * @param dir_p pointer to an initialized 'fs_read_dir_t' variable
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum * @return LV_FS_RES_OK or any error from lv_fs_res_t enum
*/ */
static lv_fs_res_t fs_dir_close(lv_fs_drv_t * drv, void * dir_p) static lv_fs_res_t fs_dir_close(lv_fs_drv_t* drv, void* dir_p)
{ {
(void)drv; /*Unused*/ (void)drv; /*Unused*/
dir_t * dp = dir_p; dir_t* dp = dir_p;
#ifndef WIN32 #if defined(ARDUINO_ARCH_ESP8266) || defined(STM32F4xx)
return LV_FS_RES_UNKNOWN;
#elif !defined(WIN32)
closedir(*dp); closedir(*dp);
#else #else
FindClose(*dp); FindClose(*dp);
*dp = INVALID_HANDLE_VALUE; *dp = INVALID_HANDLE_VALUE;
#endif #endif
return LV_FS_RES_OK; return LV_FS_RES_OK;
} }
#endif /*LV_USE_FS_IF*/ #endif /*LV_USE_FS_IF*/
#endif /*LV_FS_IF_FATFS*/ #endif /*LV_FS_IF_FATFS*/

View File

@ -83,6 +83,7 @@ lib_deps =
;AsyncTCP ;AsyncTCP
;https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip ;https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip
;https://github.com/me-no-dev/ESPAsyncTCP/archive/master.zip ;https://github.com/me-no-dev/ESPAsyncTCP/archive/master.zip
adafruit/Adafruit STMPE610@^1.1.3 ;STMPE610 touch controller
src_filter = +<*> -<.git/> -<examples/> -<test/> -<tests/> -<stm32f4/> -<lv_font_montserrat_*.c> src_filter = +<*> -<.git/> -<examples/> -<test/> -<tests/> -<stm32f4/> -<lv_font_montserrat_*.c>

View File

@ -23,6 +23,8 @@
#include "drv/touch/hasp_drv_ft5206.h" #include "drv/touch/hasp_drv_ft5206.h"
#elif TOUCH_DRIVER == 6336 #elif TOUCH_DRIVER == 6336
#include "drv/touch/hasp_drv_ft6336u.h" #include "drv/touch/hasp_drv_ft6336u.h"
#elif TOUCH_DRIVER == 610
#include "drv/touch/hasp_drv_stmpe610.h"
#else #else
//#include "tp_i2c.h" //#include "tp_i2c.h"
//#include "ft6x36.h" //#include "ft6x36.h"
@ -56,6 +58,9 @@ void drv_touch_init(uint8_t rotation)
#elif TOUCH_DRIVER == 6336 #elif TOUCH_DRIVER == 6336
FT6336U_init(); FT6336U_init();
#elif TOUCH_DRIVER == 610
STMPE610_init();
#else #else
// xpt2046_alt_drv_read(indev_driver, data); // xpt2046_alt_drv_read(indev_driver, data);
// xpt2046_read(indev_driver, data); // xpt2046_read(indev_driver, data);
@ -86,6 +91,9 @@ static inline bool drv_touchpad_getXY(int16_t* touchX, int16_t* touchY)
#elif TOUCH_DRIVER == 6336 #elif TOUCH_DRIVER == 6336
touched = FT6336U_getXY(&normal_x, &normal_y, true); touched = FT6336U_getXY(&normal_x, &normal_y, true);
#elif TOUCH_DRIVER == 610
touched = STMPE610_getXY(&normal_x, &normal_y, drv_touch_rotation, true);
#else #else
// xpt2046_alt_drv_read(indev_driver, data); // xpt2046_alt_drv_read(indev_driver, data);
// xpt2046_read(indev_driver, data); // xpt2046_read(indev_driver, data);

View File

@ -0,0 +1,69 @@
#if TOUCH_DRIVER == 610
#include <SPI.h>
#include "Adafruit_STMPE610.h"
#include "ArduinoLog.h"
#include "hasp_drv_stmpe610.h"
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 3800
#define TS_MAXX 100
#define TS_MINY 100
#define TS_MAXY 3750
static Adafruit_STMPE610 touch = Adafruit_STMPE610(STMPE_CS);
// Read touch points from global variable
bool IRAM_ATTR STMPE610_getXY(int16_t * touchX, int16_t * touchY, uint8_t touchRotation, bool debug)
{
uint16_t x, y;
uint8_t z;
if(! touch.touched()) return false;
while (! touch.bufferEmpty()) {
touch.readData(&x, &y, &z);
if(debug) Log.trace(TAG_DRVR, F("STMPE610: x=%i y=%i z=%i r=%i"), x, y, z, touchRotation);
}
touch.writeRegister8(STMPE_INT_STA, 0xFF);
if (1 == touchRotation) {
#if HX8357D_DRIVER == 1
y = map(y, TS_MINX, TS_MAXX, 0, TFT_HEIGHT);
x = map(x, TS_MINY, TS_MAXY, TFT_WIDTH, 0);
#else
x = map(x, TS_MAXX, TS_MINX, 0, TFT_WIDTH);
y = map(y, TS_MAXY, TS_MINY, 0, TFT_HEIGHT);
#endif
} else if (2 == touchRotation) {
#if HX8357D_DRIVER == 1
x = map(x, TS_MAXX, TS_MINX, TFT_WIDTH, 0);
y = map(y, TS_MAXY, TS_MINY, 0, TFT_HEIGHT);
#else
x = map(x, TS_MAXX, TS_MINX, 0, TFT_WIDTH);
y = map(y, TS_MAXY, TS_MINY, 0, TFT_HEIGHT);
#endif
} else {
#if HX8357D_DRIVER == 1
x = map(x, TS_MINX, TS_MAXX, TFT_WIDTH, 0);
y = map(y, TS_MINY, TS_MAXY, 0, TFT_HEIGHT);
#else
x = map(x, TS_MINX, TS_MAXX, 0, TFT_WIDTH);
y = map(y, TS_MINY, TS_MAXY, 0, TFT_HEIGHT);
#endif
}
*touchX = x;
*touchY = y;
return true;
}
void STMPE610_init()
{
if (! touch.begin()) {
Log.trace(TAG_DRVR, F("STMPE610 not found!"));
} else {
Log.trace(TAG_DRVR, F("STMPE610 touch driver started"));
}
}
#endif

View File

@ -0,0 +1,15 @@
/* MIT License - Copyright (c) 2020 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_DRV_STMPE610_H
#define HASP_DRV_STMPE610_H
#if TOUCH_DRIVER == 610
#include "hasp_debug.h" // for TAG_DRVR
bool IRAM_ATTR STMPE610_getXY(int16_t * touchX, int16_t * touchY, uint8_t touchRotation, bool debug);
void STMPE610_init();
#endif
#endif

View File

@ -54,25 +54,63 @@ moodlight_t moodlight;
static void dispatch_config(const char* topic, const char* payload); static void dispatch_config(const char* topic, const char* payload);
// void dispatch_group_value(uint8_t groupid, int16_t state, lv_obj_t * obj); // void dispatch_group_value(uint8_t groupid, int16_t state, lv_obj_t * obj);
static inline void dispatch_state_msg(const __FlashStringHelper* subtopic, const char* payload);
void dispatch_screenshot(const char*, const char* filename) /* Sends the payload out on the state/subtopic
*/
void dispatch_state_subtopic(const char* subtopic, const char* payload)
{ {
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 #if !defined(HASP_USE_MQTT) && !defined(HASP_USE_TASMOTA_CLIENT)
LOG_TRACE(TAG_MSGR, F("%s => %s"), subtopic, payload);
if(strlen(filename) == 0) { // no filename given
char tempfile[32];
memcpy_P(tempfile, PSTR("/screenshot.bmp"), sizeof(tempfile));
guiTakeScreenshot(tempfile);
} else if(strlen(filename) > 31 || filename[0] != '/') { // Invalid filename
LOG_WARNING(TAG_MSGR, "Invalid filename %s", filename);
} else { // Valid filename
guiTakeScreenshot(filename);
}
#else #else
LOG_WARNING(TAG_MSGR, "Failed to save %s, no storage", filename);
#if HASP_USE_MQTT > 0
switch(mqtt_send_state(subtopic, payload)) {
case MQTT_ERR_OK:
LOG_TRACE(TAG_MQTT_PUB, F("%s => %s"), subtopic, payload);
break;
case MQTT_ERR_PUB_FAIL:
LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), subtopic, payload);
break;
case MQTT_ERR_NO_CONN:
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED));
break;
default:
LOG_ERROR(TAG_MQTT, F(D_ERROR_UNKNOWN));
}
#endif #endif
#if HASP_USE_TASMOTA_CLIENT > 0
slave_send_state(subtopic, payload);
#endif
#endif
}
/* Sends the data out on the state/pxby topic
*/
void dispatch_state_object(uint8_t pageid, uint8_t btnid, const char* payload)
{
char topic[16];
snprintf_P(topic, sizeof(topic), PSTR(HASP_OBJECT_NOTATION), pageid, btnid);
dispatch_state_subtopic(topic, payload);
}
/* Takes and lv_obj and finds the pageid and objid
Then sends the data out on the state/pxby topic
*/
void dispatch_obj_data(lv_obj_t* obj, const char* data)
{
uint8_t pageid;
uint8_t objid;
if(hasp_find_id_from_obj(obj, &pageid, &objid)) {
if(!data) return;
#if HASP_USE_MQTT > 0
dispatch_state_object(pageid, objid, data);
#endif
} else {
LOG_ERROR(TAG_MSGR, F(D_OBJECT_UNKNOWN));
}
} }
// Format filesystem and erase EEPROM // Format filesystem and erase EEPROM
@ -319,28 +357,32 @@ void dispatch_text_line(const char* cmnd)
// send idle state to the client // send idle state to the client
void dispatch_output_idle_state(uint8_t state) void dispatch_output_idle_state(uint8_t state)
{ {
char topic[6];
char payload[6]; char payload[6];
switch(state) { switch(state) {
case HASP_SLEEP_LONG: case HASP_SLEEP_LONG:
memcpy_P(payload, PSTR("LONG"), 5); memcpy_P(payload, PSTR("long"), 5);
break; break;
case HASP_SLEEP_SHORT: case HASP_SLEEP_SHORT:
memcpy_P(payload, PSTR("SHORT"), 6); memcpy_P(payload, PSTR("short"), 6);
break; break;
default: default:
memcpy_P(payload, PSTR("OFF"), 4); memcpy_P(payload, PSTR("off"), 4);
} }
dispatch_state_msg(F("idle"), payload); memcpy_P(topic, PSTR("idle"), 5);
dispatch_state_subtopic(topic, payload);
} }
void dispatch_output_group_state(uint8_t groupid, uint16_t state) void dispatch_output_group_state(uint8_t groupid, uint16_t state)
{ {
char payload[64]; char payload[64];
char number[16]; // Return the current state char number[16]; // Return the current state
char topic[8];
itoa(state, number, DEC); itoa(state, number, DEC);
snprintf_P(payload, sizeof(payload), PSTR("{\"group\":%d,\"state\":\"%s\"}"), groupid, number); snprintf_P(payload, sizeof(payload), PSTR("{\"group\":%d,\"state\":\"%s\"}"), groupid, number);
dispatch_state_msg(F("output"), payload); memcpy_P(topic, PSTR("output"), 7);
dispatch_state_subtopic(topic, payload);
} }
void dispatch_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char* attribute, const char* data) void dispatch_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char* attribute, const char* data)
@ -350,7 +392,7 @@ void dispatch_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char*
char payload[32 + strlen(data) + strlen(attribute)]; char payload[32 + strlen(data) + strlen(attribute)];
snprintf_P(payload, sizeof(payload), PSTR("{\"%s\":\"%s\"}"), attribute, data); snprintf_P(payload, sizeof(payload), PSTR("{\"%s\":\"%s\"}"), attribute, data);
mqtt_send_object_state(pageid, btnid, payload); dispatch_state_object(pageid, btnid, payload);
} }
void dispatch_send_obj_attribute_int(uint8_t pageid, uint8_t btnid, const char* attribute, int32_t val) void dispatch_send_obj_attribute_int(uint8_t pageid, uint8_t btnid, const char* attribute, int32_t val)
@ -360,7 +402,7 @@ void dispatch_send_obj_attribute_int(uint8_t pageid, uint8_t btnid, const char*
char payload[64 + strlen(attribute)]; char payload[64 + strlen(attribute)];
snprintf_P(payload, sizeof(payload), PSTR("{\"%s\":%d}"), attribute, val); snprintf_P(payload, sizeof(payload), PSTR("{\"%s\":%d}"), attribute, val);
mqtt_send_object_state(pageid, btnid, payload); dispatch_state_object(pageid, btnid, payload);
} }
void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char* attribute, uint8_t r, uint8_t g, void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char* attribute, uint8_t r, uint8_t g,
@ -372,7 +414,7 @@ void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char
snprintf_P(payload, sizeof(payload), PSTR("{\"%s\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d}"), attribute, r, g, snprintf_P(payload, sizeof(payload), PSTR("{\"%s\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d}"), attribute, r, g,
b, r, g, b); b, r, g, b);
mqtt_send_object_state(pageid, btnid, payload); dispatch_state_object(pageid, btnid, payload);
} }
#if HASP_USE_CONFIG > 0 #if HASP_USE_CONFIG > 0
@ -420,6 +462,15 @@ static void dispatch_config(const char* topic, const char* payload)
haspGetConfig(settings); haspGetConfig(settings);
} }
#if HASP_USE_GPIO > 0
else if(strcasecmp_P(topic, PSTR("gpio")) == 0) {
if(update)
gpioSetConfig(settings);
else
gpioGetConfig(settings);
}
#endif
#if HASP_USE_WIFI > 0 #if HASP_USE_WIFI > 0
else if(strcasecmp_P(topic, PSTR("wifi")) == 0) { else if(strcasecmp_P(topic, PSTR("wifi")) == 0) {
if(update) if(update)
@ -459,9 +510,12 @@ static void dispatch_config(const char* topic, const char* payload)
// Send output // Send output
if(!update) { if(!update) {
char subtopic[8];
settings.remove(F("pass")); // hide password in output settings.remove(F("pass")); // hide password in output
size_t size = serializeJson(doc, buffer, sizeof(buffer)); size_t size = serializeJson(doc, buffer, sizeof(buffer));
dispatch_state_msg(F("config"), buffer); memcpy_P(subtopic, PSTR("config"), 7);
dispatch_state_subtopic(subtopic, buffer);
} }
} }
#endif // HASP_USE_CONFIG #endif // HASP_USE_CONFIG
@ -491,31 +545,34 @@ void dispatch_get_event_name(uint8_t eventid, char* buffer, size_t size)
{ {
switch(eventid) { switch(eventid) {
case HASP_EVENT_ON: case HASP_EVENT_ON:
memcpy_P(buffer, PSTR("ON"), size); memcpy_P(buffer, PSTR("on"), size);
break; break;
case HASP_EVENT_OFF: case HASP_EVENT_OFF:
memcpy_P(buffer, PSTR("OFF"), size); memcpy_P(buffer, PSTR("off"), size);
break; break;
case HASP_EVENT_UP: case HASP_EVENT_UP:
memcpy_P(buffer, PSTR("UP"), size); memcpy_P(buffer, PSTR("up"), size);
break; break;
case HASP_EVENT_DOWN: case HASP_EVENT_DOWN:
memcpy_P(buffer, PSTR("DOWN"), size); memcpy_P(buffer, PSTR("down"), size);
break; break;
case HASP_EVENT_SHORT: case HASP_EVENT_SHORT:
memcpy_P(buffer, PSTR("SHORT"), size); memcpy_P(buffer, PSTR("short"), size);
break; break;
case HASP_EVENT_LONG: case HASP_EVENT_LONG:
memcpy_P(buffer, PSTR("LONG"), size); memcpy_P(buffer, PSTR("long"), size);
break; break;
case HASP_EVENT_HOLD: case HASP_EVENT_HOLD:
memcpy_P(buffer, PSTR("HOLD"), size); memcpy_P(buffer, PSTR("hold"), size);
break; break;
case HASP_EVENT_LOST: case HASP_EVENT_LOST:
memcpy_P(buffer, PSTR("LOST"), size); memcpy_P(buffer, PSTR("lost"), size);
break;
case HASP_EVENT_CHANGED:
memcpy_P(buffer, PSTR("changed"), size);
break; break;
default: default:
memcpy_P(buffer, PSTR("UNKNOWN"), size); memcpy_P(buffer, PSTR("unknown"), size);
} }
} }
@ -523,12 +580,14 @@ void dispatch_get_event_name(uint8_t eventid, char* buffer, size_t size)
void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid) void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid)
{ {
char payload[64]; char payload[64];
char topic[8];
char event[8]; char event[8];
dispatch_get_event_name(eventid, event, sizeof(event)); dispatch_get_event_name(eventid, event, sizeof(event));
snprintf_P(payload, sizeof(payload), PSTR("{\"pin\":%d,\"group\":%d,\"event\":\"%s\"}"), pin, group, event); snprintf_P(payload, sizeof(payload), PSTR("{\"pin\":%d,\"group\":%d,\"event\":\"%s\"}"), pin, group, event);
#if HASP_USE_MQTT > 0 #if HASP_USE_MQTT > 0
mqtt_send_state(F("input"), payload); memcpy_P(topic, PSTR("input"), 6);
dispatch_state_subtopic(topic, payload);
#endif #endif
// update outputstates // update outputstates
@ -536,45 +595,67 @@ void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid)
} }
#endif #endif
void dispatch_object_event(lv_obj_t* obj, uint8_t eventid) /* ============================== Event Senders ============================ */
// Send out the event that occured
void dispatch_object_generic_event(lv_obj_t* obj, uint8_t eventid)
{ {
char topic[8]; char data[40];
char payload[8]; char eventname[8];
uint8_t pageid, objid;
snprintf_P(topic, sizeof(topic), PSTR("event")); dispatch_get_event_name(eventid, eventname, sizeof(eventname));
dispatch_get_event_name(eventid, payload, sizeof(payload)); snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\"}"), eventname);
dispatch_obj_data(obj, data);
if(hasp_find_id_from_obj(obj, &pageid, &objid)) {
dispatch_send_obj_attribute_str(pageid, objid, topic, payload);
}
// dispatch_group_onoff(obj->user_data.groupid, dispatch_get_event_state(eventid), obj);
} }
// Send out the on/off event, with the val
void dispatch_object_toggle_event(lv_obj_t* obj, bool state)
{
char data[40];
char eventname[8];
dispatch_get_event_name(state, eventname, sizeof(eventname));
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"%s\",\"val\":%d}"), eventname, state);
dispatch_obj_data(obj, data);
}
// Send out the changed event, with the val
void dispatch_object_value_changed(lv_obj_t* obj, int16_t state) void dispatch_object_value_changed(lv_obj_t* obj, int16_t state)
{ {
char topic[4]; char data[48];
hasp_update_sleep_state(); // wakeup? snprintf_P(data, sizeof(data), PSTR("{\"event\":\"changed\",\"val\":%d}"), state);
snprintf_P(topic, sizeof(topic), PSTR("val")); dispatch_obj_data(obj, data);
hasp_send_obj_attribute_int(obj, topic, state); }
// Send out the changed event, with the val and text
void dispatch_object_selection_changed(lv_obj_t* obj, int16_t val, const char* text)
{
char data[200];
snprintf_P(data, sizeof(data), PSTR("{\"event\":\"changed\",\"val\":%d,\"text\":\"%s\"}"), val, text);
dispatch_obj_data(obj, data);
}
// Send out the changed event, with the color
void dispatch_object_color_changed(lv_obj_t* obj, lv_color_t color)
{
char data[80];
lv_color32_t c32;
c32.full = lv_color_to32(color);
snprintf_P(data, sizeof(data),
PSTR("{\"event\":\"changed\",\"color\":\"#%02x%02x%02x\",\"r\":%d,\"g\":%d,\"b\":%d}"), c32.ch.red,
c32.ch.green, c32.ch.blue, c32.ch.red, c32.ch.green, c32.ch.blue);
dispatch_obj_data(obj, data);
} }
/********************************************** Output States ******************************************/ /********************************************** Output States ******************************************/
/*
static inline void dispatch_state_msg(const __FlashStringHelper* subtopic, const char* payload) static inline void dispatch_state_msg(const __FlashStringHelper* subtopic, const char* payload)
{ {
#if !defined(HASP_USE_MQTT) && !defined(HASP_USE_TASMOTA_CLIENT)
LOG_TRACE(TAG_MSGR, F("%s => %s"), String(subtopic).c_str(), payload); }*/
#else
#if HASP_USE_MQTT > 0
mqtt_send_state(subtopic, payload);
#endif
#if HASP_USE_TASMOTA_CLIENT > 0
slave_send_state(subtopic, payload);
#endif
#endif
}
// void dispatch_group_onoff(uint8_t groupid, uint16_t eventid, lv_obj_t * obj) // void dispatch_group_onoff(uint8_t groupid, uint16_t eventid, lv_obj_t * obj)
// { // {
@ -615,6 +696,25 @@ void dispatch_normalized_group_value(uint8_t groupid, uint16_t value, lv_obj_t*
/********************************************** Native Commands ****************************************/ /********************************************** Native Commands ****************************************/
void dispatch_screenshot(const char*, const char* filename)
{
#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0
if(strlen(filename) == 0) { // no filename given
char tempfile[32];
memcpy_P(tempfile, PSTR("/screenshot.bmp"), sizeof(tempfile));
guiTakeScreenshot(tempfile);
} else if(strlen(filename) > 31 || filename[0] != '/') { // Invalid filename
LOG_WARNING(TAG_MSGR, "Invalid filename %s", filename);
} else { // Valid filename
guiTakeScreenshot(filename);
}
#else
LOG_WARNING(TAG_MSGR, "Failed to save %s, no storage", filename);
#endif
}
void dispatch_parse_json(const char*, const char* payload) void dispatch_parse_json(const char*, const char* payload)
{ // Parse an incoming JSON array into individual commands { // Parse an incoming JSON array into individual commands
/* if(strPayload.endsWith(",]")) { /* if(strPayload.endsWith(",]")) {
@ -710,10 +810,12 @@ void dispatch_parse_jsonl(const char*, const char* payload)
void dispatch_output_current_page() void dispatch_output_current_page()
{ {
// Log result char topic[8];
char payload[4]; char payload[8];
itoa(haspGetPage(), payload, DEC);
dispatch_state_msg(F("page"), payload); memcpy_P(topic, PSTR("page"), 5);
snprintf_P(payload, sizeof(payload), PSTR("%d"), haspGetPage());
dispatch_state_subtopic(topic, payload);
} }
// Get or Set a page // Get or Set a page
@ -776,9 +878,12 @@ void dispatch_dim(const char*, const char* level)
// Set the current state // Set the current state
if(strlen(level) != 0) haspDevice.set_backlight_level(atoi(level)); if(strlen(level) != 0) haspDevice.set_backlight_level(atoi(level));
char payload[5]; char topic[8];
itoa(haspDevice.get_backlight_level(), payload, DEC); char payload[8];
dispatch_state_msg(F("dim"), payload);
memcpy_P(topic, PSTR("dim"), 4);
snprintf_P(payload, sizeof(payload), PSTR("%d"), haspDevice.get_backlight_level());
dispatch_state_subtopic(topic, payload);
} }
void dispatch_moodlight(const char* topic, const char* payload) void dispatch_moodlight(const char* topic, const char* payload)
@ -802,8 +907,8 @@ void dispatch_moodlight(const char* topic, const char* payload)
moodlight.power = Utilities::is_true(json[F("state")].as<std::string>().c_str()); moodlight.power = Utilities::is_true(json[F("state")].as<std::string>().c_str());
if(!json[F("r")].isNull()) moodlight.r = json[F("r")].as<uint8_t>(); if(!json[F("r")].isNull()) moodlight.r = json[F("r")].as<uint8_t>();
if(!json[F("g")].isNull()) moodlight.r = json[F("g")].as<uint8_t>(); if(!json[F("g")].isNull()) moodlight.g = json[F("g")].as<uint8_t>();
if(!json[F("b")].isNull()) moodlight.r = json[F("b")].as<uint8_t>(); if(!json[F("b")].isNull()) moodlight.b = json[F("b")].as<uint8_t>();
if(!json[F("color")].isNull()) { if(!json[F("color")].isNull()) {
if(!json[F("color")]["r"].isNull()) { if(!json[F("color")]["r"].isNull()) {
@ -834,11 +939,14 @@ void dispatch_moodlight(const char* topic, const char* payload)
// Return the current state // Return the current state
char buffer[128]; char buffer[128];
char out_topic[16];
memcpy_P(out_topic, PSTR("moodlight"), 10);
snprintf_P( snprintf_P(
// buffer, sizeof(buffer), PSTR("{\"state\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%u,\"g\":%u,\"b\":%u}"), // buffer, sizeof(buffer),
// PSTR("{\"state\":\"%s\",\"color\":\"#%02x%02x%02x\",\"r\":%u,\"g\":%u,\"b\":%u}"),
buffer, sizeof(buffer), PSTR("{\"state\":\"%s\",\"color\":{\"r\":%u,\"g\":%u,\"b\":%u}}"), buffer, sizeof(buffer), PSTR("{\"state\":\"%s\",\"color\":{\"r\":%u,\"g\":%u,\"b\":%u}}"),
moodlight.power ? "ON" : "OFF", moodlight.r, moodlight.g, moodlight.b); moodlight.power ? "on" : "off", moodlight.r, moodlight.g, moodlight.b);
dispatch_state_msg(F("moodlight"), buffer); dispatch_state_subtopic(out_topic, buffer);
} }
void dispatch_backlight(const char*, const char* payload) void dispatch_backlight(const char*, const char* payload)
@ -847,9 +955,11 @@ void dispatch_backlight(const char*, const char* payload)
if(strlen(payload) != 0) haspDevice.set_backlight_power(Utilities::is_true(payload)); if(strlen(payload) != 0) haspDevice.set_backlight_power(Utilities::is_true(payload));
// Return the current state // Return the current state
char topic[8];
char buffer[4]; char buffer[4];
memcpy_P(buffer, haspDevice.get_backlight_power() ? PSTR("ON") : PSTR("OFF"), sizeof(buffer)); memcpy_P(topic, PSTR("light"), 6);
dispatch_state_msg(F("light"), buffer); memcpy_P(buffer, haspDevice.get_backlight_power() ? PSTR("on") : PSTR("off"), sizeof(buffer));
dispatch_state_subtopic(topic, buffer);
} }
void dispatch_web_update(const char*, const char* espOtaUrl) void dispatch_web_update(const char*, const char* espOtaUrl)
@ -916,12 +1026,12 @@ void dispatch_output_statusupdate(const char*, const char*)
strcat(data, buffer); strcat(data, buffer);
#endif #endif
snprintf_P(buffer, sizeof(buffer), PSTR("\"heapFree\":%u,\"heapFrag\":%u,\"espCore\":\"%s\","), snprintf_P(buffer, sizeof(buffer), PSTR("\"heapFree\":%u,\"heapFrag\":%u,\"core\":\"%s\","),
haspDevice.get_free_heap(), haspDevice.get_heap_fragmentation(), haspDevice.get_core_version()); haspDevice.get_free_heap(), haspDevice.get_heap_fragmentation(), haspDevice.get_core_version());
strcat(data, buffer); strcat(data, buffer);
snprintf_P(buffer, sizeof(buffer), PSTR("\"espCanUpdate\":\"false\",\"page\":%u,\"numPages\":%u,"), snprintf_P(buffer, sizeof(buffer), PSTR("\"canUpdate\":\"false\",\"page\":%u,\"numPages\":%u,"), haspGetPage(),
haspGetPage(), (HASP_NUM_PAGES)); (HASP_NUM_PAGES));
strcat(data, buffer); strcat(data, buffer);
#if defined(ARDUINO_ARCH_ESP8266) #if defined(ARDUINO_ARCH_ESP8266)
@ -933,7 +1043,10 @@ void dispatch_output_statusupdate(const char*, const char*)
Utilities::tft_driver_name().c_str(), (TFT_WIDTH), (TFT_HEIGHT)); Utilities::tft_driver_name().c_str(), (TFT_WIDTH), (TFT_HEIGHT));
strcat(data, buffer); strcat(data, buffer);
} }
mqtt_send_state(F("statusupdate"), data);
char topic[16];
memcpy_P(topic, PSTR("statusupdate"), 13);
dispatch_state_subtopic(topic, data);
dispatchLastMillis = millis(); dispatchLastMillis = millis();
/* if(updateEspAvailable) { /* if(updateEspAvailable) {

View File

@ -22,7 +22,9 @@ enum hasp_event_t { // even = released, odd = pressed
HASP_EVENT_LONG = 5, HASP_EVENT_LONG = 5,
HASP_EVENT_LOST = 6, HASP_EVENT_LOST = 6,
HASP_EVENT_HOLD = 7, HASP_EVENT_HOLD = 7,
HASP_EVENT_DOUBLE = 8 HASP_EVENT_DOUBLE = 8,
HASP_EVENT_CHANGED = 32
}; };
/* ===== Default Event Processors ===== */ /* ===== Default Event Processors ===== */
@ -60,7 +62,6 @@ void dispatch_output_statusupdate(const char*, const char*);
void dispatch_current_state(); void dispatch_current_state();
void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid); void dispatch_gpio_input_event(uint8_t pin, uint8_t group, uint8_t eventid);
void dispatch_object_event(lv_obj_t* obj, uint8_t eventid);
bool dispatch_get_event_state(uint8_t eventid); bool dispatch_get_event_state(uint8_t eventid);
void dispatch_get_event_name(uint8_t eventid, char* buffer, size_t size); void dispatch_get_event_name(uint8_t eventid, char* buffer, size_t size);
void dispatch_object_value_changed(lv_obj_t* obj, int16_t state); void dispatch_object_value_changed(lv_obj_t* obj, int16_t state);
@ -72,6 +73,12 @@ void dispatch_send_obj_attribute_int(uint8_t pageid, uint8_t btnid, const char*
void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char* attribute, uint8_t r, uint8_t g, void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char* attribute, uint8_t r, uint8_t g,
uint8_t b); uint8_t b);
void dispatch_object_generic_event(lv_obj_t* obj, uint8_t eventid);
void dispatch_object_toggle_event(lv_obj_t* obj, bool state);
void dispatch_object_value_changed(lv_obj_t* obj, int16_t state);
void dispatch_object_selection_changed(lv_obj_t* obj, int16_t val, const char* text);
void dispatch_object_color_changed(lv_obj_t* obj, lv_color_t color);
/* ===== Getter and Setter Functions ===== */ /* ===== Getter and Setter Functions ===== */
/* ===== Read/Write Configuration ===== */ /* ===== Read/Write Configuration ===== */
@ -79,8 +86,8 @@ void dispatch_send_obj_attribute_color(uint8_t pageid, uint8_t btnid, const char
/* ===== Structs and Constants ===== */ /* ===== Structs and Constants ===== */
struct haspCommand_t struct haspCommand_t
{ {
void (*func)(const char*, const char*);
const char* p_cmdstr; const char* p_cmdstr;
void (*func)(const char*, const char*);
}; };
#endif #endif

36
src/hasp/hasp_lvfs.cpp Normal file
View File

@ -0,0 +1,36 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#include "lv_fs_if.h"
#include "hasp_conf.h" // include first
#include "hasp_debug.h"
void filesystem_list_path(const char* path)
{
lv_fs_dir_t dir;
lv_fs_res_t res;
res = lv_fs_dir_open(&dir, path);
if(res != LV_FS_RES_OK) {
LOG_ERROR(TAG_LVFS, "Error opening directory %s", path);
} else {
char fn[256];
while(1) {
res = lv_fs_dir_read(&dir, fn);
if(res != LV_FS_RES_OK) {
LOG_ERROR(TAG_LVFS, "Directory %s can not be read", path);
break;
}
/*fn is empty, if not more files to read*/
if(strlen(fn) == 0) {
LOG_WARNING(TAG_LVFS, "Directory %s listing complete", path);
break;
}
LOG_VERBOSE(TAG_LVFS, D_BULLET "%s", fn);
}
}
lv_fs_dir_close(&dir);
}

9
src/hasp/hasp_lvfs.h Normal file
View File

@ -0,0 +1,9 @@
/* MIT License - Copyright (c) 2019-2021 Francis Van Roie
For full license information read the LICENSE file in the project folder */
#ifndef HASP_LVFS_H
#define HASP_LVFS_H
void filesystem_list_path(const char* path);
#endif

View File

@ -269,6 +269,23 @@ void hasp_send_obj_attribute_color(lv_obj_t* obj, const char* attribute, lv_colo
// ##################### Event Handlers ######################################################## // ##################### Event Handlers ########################################################
/**
* Called when a press on the system layer is detected
* @param obj pointer to a button matrix
* @param event type of event that occured
*/
void wakeup_event_handler(lv_obj_t* obj, lv_event_t event)
{
if(obj == lv_disp_get_layer_sys(NULL)) {
hasp_update_sleep_state(); // wakeup?
if(event == LV_EVENT_CLICKED) {
lv_obj_set_click(obj, false); // disable first touch
LOG_VERBOSE(TAG_HASP, F("Wakeup touch disabled"));
}
}
}
/** /**
* Called when a button-style object is clicked * Called when a button-style object is clicked
* @param obj pointer to a button object * @param obj pointer to a button object
@ -317,7 +334,7 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event)
return; return;
case LV_EVENT_VALUE_CHANGED: case LV_EVENT_VALUE_CHANGED:
LOG_WARNING(TAG_HASP, F("Value changed Event %d occured"), event); LOG_WARNING(TAG_HASP, F("Value changed Event %d occured"), event); // Shouldn't happen in this event handler
last_press_was_short = false; last_press_was_short = false;
return; return;
@ -333,28 +350,11 @@ void generic_event_handler(lv_obj_t* obj, lv_event_t event)
return; return;
} }
hasp_update_sleep_state(); // wakeup? hasp_update_sleep_state(); // wakeup?
dispatch_object_event(obj, eventid); // send object event dispatch_object_generic_event(obj, eventid); // send object event
dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(dispatch_get_event_state(eventid), 0, 1), obj); dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(dispatch_get_event_state(eventid), 0, 1), obj);
} }
/**
* Called when a press on the system layer is detected
* @param obj pointer to a button matrix
* @param event type of event that occured
*/
void wakeup_event_handler(lv_obj_t* obj, lv_event_t event)
{
if(obj == lv_disp_get_layer_sys(NULL)) {
hasp_update_sleep_state(); // wakeup?
if(event == LV_EVENT_CLICKED) {
lv_obj_set_click(obj, false); // disable first touch
LOG_VERBOSE(TAG_HASP, F("Wakeup touch disabled"));
}
}
}
/** /**
* Called when a object state is toggled on/off * Called when a object state is toggled on/off
* @param obj pointer to a switch object * @param obj pointer to a switch object
@ -363,7 +363,7 @@ void wakeup_event_handler(lv_obj_t* obj, lv_event_t event)
void toggle_event_handler(lv_obj_t* obj, lv_event_t event) void toggle_event_handler(lv_obj_t* obj, lv_event_t event)
{ {
if(event == LV_EVENT_VALUE_CHANGED) { if(event == LV_EVENT_VALUE_CHANGED) {
char property[4]; char property[36]; // 4 for val only
bool val = 0; bool val = 0;
hasp_update_sleep_state(); // wakeup? hasp_update_sleep_state(); // wakeup?
@ -385,8 +385,11 @@ void toggle_event_handler(lv_obj_t* obj, lv_event_t event)
return; return;
} }
snprintf_P(property, sizeof(property), PSTR("val")); // snprintf_P(property, sizeof(property), PSTR("val"));
hasp_send_obj_attribute_int(obj, property, val); // hasp_send_obj_attribute_int(obj, property, val);
hasp_update_sleep_state(); // wakeup?
dispatch_object_toggle_event(obj, val);
dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, 0, 1), obj); dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, 0, 1), obj);
} else if(event == LV_EVENT_DELETE) { } else if(event == LV_EVENT_DELETE) {
@ -437,7 +440,7 @@ static void selector_event_handler(lv_obj_t* obj, lv_event_t event)
const char* txt = lv_table_get_cell_value(obj, row, col); const char* txt = lv_table_get_cell_value(obj, row, col);
strncpy(buffer, txt, sizeof(buffer)); strncpy(buffer, txt, sizeof(buffer));
snprintf_P(property, sizeof(property), PSTR("row\":%d,\"col\":%d,\"txt"), row, col); snprintf_P(property, sizeof(property), PSTR("row\":%d,\"col\":%d,\"text"), row, col);
hasp_send_obj_attribute_str(obj, property, buffer); hasp_send_obj_attribute_str(obj, property, buffer);
return; return;
} }
@ -447,8 +450,10 @@ static void selector_event_handler(lv_obj_t* obj, lv_event_t event)
} }
// set the property // set the property
snprintf_P(property, sizeof(property), PSTR("val\":%d,\"text"), val); // snprintf_P(property, sizeof(property), PSTR("val\":%d,\"text"), val);
hasp_send_obj_attribute_str(obj, property, buffer); // hasp_send_obj_attribute_str(obj, property, buffer);
dispatch_object_selection_changed(obj, val, buffer);
if(max > 0) dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, 0, max), obj); if(max > 0) dispatch_normalized_group_value(obj->user_data.groupid, NORMALIZE(val, 0, max), obj);
} else if(event == LV_EVENT_DELETE) { } else if(event == LV_EVENT_DELETE) {
@ -481,6 +486,7 @@ void slider_event_handler(lv_obj_t* obj, lv_event_t event)
int16_t val = 0; int16_t val = 0;
int16_t min = 0; int16_t min = 0;
int16_t max = 0; int16_t max = 0;
hasp_update_sleep_state(); // wakeup?
if(obj->user_data.objid == LV_HASP_SLIDER) { if(obj->user_data.objid == LV_HASP_SLIDER) {
val = lv_slider_get_value(obj); val = lv_slider_get_value(obj);
@ -514,7 +520,9 @@ static void cpicker_event_handler(lv_obj_t* obj, lv_event_t event)
if(event == LV_EVENT_VALUE_CHANGED) { if(event == LV_EVENT_VALUE_CHANGED) {
hasp_update_sleep_state(); // wakeup? hasp_update_sleep_state(); // wakeup?
hasp_send_obj_attribute_color(obj, color, lv_cpicker_get_color(obj)); // hasp_send_obj_attribute_color(obj, color, lv_cpicker_get_color(obj));
dispatch_object_color_changed(obj, lv_cpicker_get_color(obj));
} else if(event == LV_EVENT_DELETE) { } else if(event == LV_EVENT_DELETE) {
LOG_VERBOSE(TAG_HASP, F(D_OBJECT_DELETED)); LOG_VERBOSE(TAG_HASP, F(D_OBJECT_DELETED));
hasp_object_delete(obj); hasp_object_delete(obj);

View File

@ -23,8 +23,7 @@
#include "hasp_gui.h" #include "hasp_gui.h"
#include "hasp_oobe.h" #include "hasp_oobe.h"
#include "hasp/hasp_dispatch.h" #include "hasplib.h"
#include "hasp/hasp.h"
#if defined(WINDOWS) || defined(POSIX) #if defined(WINDOWS) || defined(POSIX)
#include "display/monitor.h" #include "display/monitor.h"
@ -194,8 +193,12 @@ void guiSetup(void)
/* Initialize Filesystems */ /* Initialize Filesystems */
#if LV_USE_FS_IF != 0 #if LV_USE_FS_IF != 0
_lv_fs_init(); // lvgl File System // _lv_fs_init(); // lvgl File System -- not neaded, it done in lv_init() when LV_USE_FILESYSTEM is set
LOG_VERBOSE(TAG_LVGL, F("Filesystem : Enabled"));
lv_fs_if_init(); // auxilary file system drivers lv_fs_if_init(); // auxilary file system drivers
filesystem_list_path("S:/");
#else
LOG_VERBOSE(TAG_LVGL, F("Filesystem : Disabled"));
#endif #endif
/* Initialize PNG decoder */ /* Initialize PNG decoder */

View File

@ -6,5 +6,6 @@
#include "hasp/hasp_object.h" #include "hasp/hasp_object.h"
#include "hasp/hasp_parser.h" #include "hasp/hasp_parser.h"
#include "hasp/hasp_utilities.h" #include "hasp/hasp_utilities.h"
#include "hasp/hasp_lvfs.h"
#include "hasp/lv_theme_hasp.h" #include "hasp/lv_theme_hasp.h"

View File

@ -6,6 +6,7 @@
#define D_SSID "Ssid:" #define D_SSID "Ssid:"
#define D_ERROR_OUT_OF_MEMORY "Out of memory" #define D_ERROR_OUT_OF_MEMORY "Out of memory"
#define D_ERROR_UNKNOWN "Unkown error"
#define D_CONFIG_NOT_CHANGED "Settings did not change" #define D_CONFIG_NOT_CHANGED "Settings did not change"
#define D_CONFIG_CHANGED "Settings changed" #define D_CONFIG_CHANGED "Settings changed"

View File

@ -6,6 +6,7 @@
#define D_SSID "Ssid:" #define D_SSID "Ssid:"
#define D_ERROR_OUT_OF_MEMORY "Geen geheugen bechikbaar" #define D_ERROR_OUT_OF_MEMORY "Geen geheugen bechikbaar"
#define D_ERROR_UNKNOWN "Unbekende fout"
#define D_CONFIG_NOT_CHANGED "Instellingen ongewijzigd" #define D_CONFIG_NOT_CHANGED "Instellingen ongewijzigd"
#define D_CONFIG_CHANGED "Instellingen gewijzigd" #define D_CONFIG_CHANGED "Instellingen gewijzigd"

View File

@ -57,9 +57,9 @@ void setup()
configSetup(); // also runs debugPreSetup(), debugSetup() and debugStart() configSetup(); // also runs debugPreSetup(), debugSetup() and debugStart()
#endif #endif
dispatchSetup();
guiSetup(); guiSetup();
debugSetup(); // Init the console debugSetup(); // Init the console
dispatchSetup(); // for hasp and oobe
#if HASP_USE_CONFIG > 0 #if HASP_USE_CONFIG > 0
if(!oobeSetup()) if(!oobeSetup())
@ -100,7 +100,7 @@ void setup()
telnetSetup(); telnetSetup();
#endif #endif
#if HASP_USE_TASMOTA_CLINET > 0 #if HASP_USE_TASMOTA_CLIENT > 0
slaveSetup(); slaveSetup();
#endif #endif

View File

@ -110,14 +110,14 @@ void setup()
lv_log_register_print_cb(debugLvglLogEvent); lv_log_register_print_cb(debugLvglLogEvent);
lv_init(); lv_init();
haspDevice.init(); haspDevice.init(); // hardware setup
// hal_setup(); // hal_setup();
dispatchSetup();
guiSetup(); guiSetup();
// debugSetup(); // Init the console // debugSetup(); // Init the console
printf("%s %d\n", __FILE__, __LINE__); printf("%s %d\n", __FILE__, __LINE__);
dispatchSetup(); // for hasp and oobe
haspSetup(); haspSetup();
#if HASP_USE_MQTT > 0 #if HASP_USE_MQTT > 0

View File

@ -9,9 +9,20 @@
#include "hasp_conf.h" #include "hasp_conf.h"
#if defined(WINDOWS) || defined(POSIX)
#define __FlashStringHelper char // #if defined(WINDOWS) || defined(POSIX)
#endif // #define __FlashStringHelper char
// #endif
enum hasp_mqtt_error_t {
MQTT_ERR_OK = 0,
MQTT_ERR_DISABLED = -1,
MQTT_ERR_NO_CONN = -2,
MQTT_ERR_SUB_FAIL = -3,
MQTT_ERR_PUB_FAIL = -4,
MQTT_ERR_UNKNOWN = -128
};
void mqttSetup(); void mqttSetup();
void mqttLoop(); void mqttLoop();
@ -19,10 +30,9 @@ void mqttEvery5Seconds(bool wifiIsConnected);
void mqttStart(); void mqttStart();
void mqttStop(); void mqttStop();
void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, char* payload); int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload);
void mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload); int mqtt_send_state(const char* subtopic, const char* payload);
int mqttPublish(const char* topic, const char* payload, size_t len, bool retain);
bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain);
bool mqttIsConnected(); bool mqttIsConnected();

View File

@ -151,7 +151,7 @@ void mqtt_ha_register_switch(uint8_t page, uint8_t id)
doc[F("t")] = buffer; // topic doc[F("t")] = buffer; // topic
doc[F("atype")] = F("binary_sensor"); // automation_type doc[F("atype")] = F("binary_sensor"); // automation_type
doc[F("pl")] = F("SHORT"); // payload doc[F("pl")] = F("short"); // payload
doc[F("type")] = F("button_short_release"); doc[F("type")] = F("button_short_release");
snprintf_P(buffer, sizeof(buffer), PSTR("%s/device_automation/%s/" HASP_OBJECT_NOTATION "_%s/config"), snprintf_P(buffer, sizeof(buffer), PSTR("%s/device_automation/%s/" HASP_OBJECT_NOTATION "_%s/config"),
@ -195,8 +195,8 @@ void mqtt_ha_register_backlight()
mqtt_ha_add_device_ids(doc); mqtt_ha_add_device_ids(doc);
mqtt_ha_add_unique_id(doc, item); mqtt_ha_add_unique_id(doc, item);
// doc[F("pl_on")] = F("ON"); // doc[F("pl_on")] = F("on");
// doc[F("pl_off")] = F("OFF"); // doc[F("pl_off")] = F("off");
char buffer[128]; char buffer[128];
snprintf_P(buffer, sizeof(buffer), PSTR("%s/light/%s/%s/config"), discovery_prefix, haspDevice.get_hostname(), snprintf_P(buffer, sizeof(buffer), PSTR("%s/light/%s/%s/config"), discovery_prefix, haspDevice.get_hostname(),
@ -341,8 +341,8 @@ device:
"bri_stat_t": "~/state/dim", "bri_stat_t": "~/state/dim",
"bri_cmd_t": "~/command/dim", "bri_cmd_t": "~/command/dim",
"bri_scl": 100, "bri_scl": 100,
"pl_on": "ON", "pl_on": "on",
"pl_off": "OFF" "pl_off": "off"
} }
{ {

View File

@ -343,7 +343,7 @@ void mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload)
mqttPublish(tmp_topic, payload, false); mqttPublish(tmp_topic, payload, false);
} }
void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, char* payload) void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload)
{ {
char tmp_topic[strlen(mqttNodeTopic) + 20]; char tmp_topic[strlen(mqttNodeTopic) + 20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/p%ub%u"), mqttNodeTopic, pageid, btnid); snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/p%ub%u"), mqttNodeTopic, pageid, btnid);

View File

@ -106,7 +106,7 @@ int disc_finished = 0;
int subscribed = 0; int subscribed = 0;
int connected = 0; int connected = 0;
bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain); int mqttPublish(const char* topic, const char* payload, size_t len, bool retain);
/* ===== Paho event callbacks ===== */ /* ===== Paho event callbacks ===== */
@ -207,30 +207,28 @@ void mqtt_subscribe(void* context, const char* topic)
/* ===== Local HASP MQTT functions ===== */ /* ===== Local HASP MQTT functions ===== */
bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain) int mqttPublish(const char* topic, const char* payload, size_t len, bool retain)
{ {
if(mqttIsConnected()) { if(!mqttIsConnected()) return MQTT_ERR_NO_CONN;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
pubmsg.payload = (char*)payload; MQTTClient_message pubmsg = MQTTClient_message_initializer;
pubmsg.payloadlen = len; // (int)strlen(payload); MQTTClient_deliveryToken token;
pubmsg.qos = QOS;
pubmsg.retained = retain;
MQTTClient_publishMessage(mqtt_client, topic, &pubmsg, &token); pubmsg.payload = (char*)payload;
int rc = MQTTClient_waitForCompletion(mqtt_client, token, TIMEOUT); pubmsg.payloadlen = len; // (int)strlen(payload);
pubmsg.qos = QOS;
pubmsg.retained = retain;
if(rc != MQTTCLIENT_SUCCESS) { MQTTClient_publishMessage(mqtt_client, topic, &pubmsg, &token);
LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " '%s' => %s"), topic, payload); int rc = MQTTClient_waitForCompletion(mqtt_client, token, TIMEOUT);
} else {
LOG_TRACE(TAG_MQTT_PUB, F("'%s' => %s OK"), topic, payload); if(rc != MQTTCLIENT_SUCCESS) {
return true; LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " '%s' => %s"), topic, payload);
} return MQTT_ERR_PUB_FAIL;
} else { } else {
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED)); LOG_TRACE(TAG_MQTT_PUB, F("'%s' => %s OK"), topic, payload);
return MQTT_ERR_OK;
} }
return false;
} }
// static bool mqttPublish(const char* topic, const char* payload, bool retain) // static bool mqttPublish(const char* topic, const char* payload, bool retain)
@ -245,19 +243,19 @@ bool mqttIsConnected()
return connected == 1; return connected == 1;
} }
void mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload) int mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload)
{ {
char tmp_topic[strlen(mqttNodeTopic) + 20]; char tmp_topic[strlen(mqttNodeTopic) + 20];
// printf(("%sstate/%s\n"), mqttNodeTopic, subtopic); // printf(("%sstate/%s\n"), mqttNodeTopic, subtopic);
snprintf_P(tmp_topic, sizeof(tmp_topic), ("%sstate/%s"), mqttNodeTopic, subtopic); snprintf_P(tmp_topic, sizeof(tmp_topic), ("%sstate/%s"), mqttNodeTopic, subtopic);
mqttPublish(tmp_topic, payload, strlen(payload), false); return mqttPublish(tmp_topic, payload, strlen(payload), false);
} }
void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, char* payload) int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload)
{ {
char tmp_topic[strlen(mqttNodeTopic) + 20]; char tmp_topic[strlen(mqttNodeTopic) + 20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/p%ub%u"), mqttNodeTopic, pageid, btnid); snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/p%ub%u"), mqttNodeTopic, pageid, btnid);
mqttPublish(tmp_topic, payload, strlen(payload), false); return mqttPublish(tmp_topic, payload, strlen(payload), false);
} }
static void onConnect(void* context) static void onConnect(void* context)

View File

@ -89,25 +89,21 @@ char mqttGroupName[16] = MQTT_GROUPNAME;
uint16_t mqttPort = MQTT_PORT; uint16_t mqttPort = MQTT_PORT;
PubSubClient mqttClient(mqttNetworkClient); PubSubClient mqttClient(mqttNetworkClient);
bool mqttPublish(const char* topic, const char* payload, size_t len, bool retain) int mqttPublish(const char* topic, const char* payload, size_t len, bool retain)
{ {
if(mqttIsConnected()) { if(!mqttEnabled) return MQTT_ERR_DISABLED;
if(mqttClient.beginPublish(topic, len, retain)) { if(!mqttClient.connected()) return MQTT_ERR_NO_CONN;
mqttClient.write((uint8_t*)payload, len);
mqttClient.endPublish();
LOG_TRACE(TAG_MQTT_PUB, F("%s => %s"), topic, payload); if(mqttClient.beginPublish(topic, len, retain)) {
return true; mqttClient.write((uint8_t*)payload, len);
} else { mqttClient.endPublish();
LOG_ERROR(TAG_MQTT_PUB, F(D_MQTT_FAILED " %s => %s"), topic, payload); return MQTT_ERR_OK;
}
} else {
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_CONNECTED));
} }
return false;
return MQTT_ERR_PUB_FAIL;
} }
static bool mqttPublish(const char* topic, const char* payload, bool retain) int mqttPublish(const char* topic, const char* payload, bool retain)
{ {
return mqttPublish(topic, payload, strlen(payload), retain); return mqttPublish(topic, payload, strlen(payload), retain);
} }
@ -132,18 +128,18 @@ void mqtt_send_lwt(bool online)
bool res = mqttPublish(tmp_topic, tmp_payload, len, true); bool res = mqttPublish(tmp_topic, tmp_payload, len, true);
} }
void mqtt_send_object_state(uint8_t pageid, uint8_t btnid, char* payload) int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload)
{ {
char tmp_topic[strlen(mqttNodeTopic) + 16]; char tmp_topic[strlen(mqttNodeTopic) + 16];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/" HASP_OBJECT_NOTATION), mqttNodeTopic, pageid, btnid); snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/" HASP_OBJECT_NOTATION), mqttNodeTopic, pageid, btnid);
mqttPublish(tmp_topic, payload, false); return mqttPublish(tmp_topic, payload, false);
} }
void mqtt_send_state(const __FlashStringHelper* subtopic, const char* payload) int mqtt_send_state(const char* subtopic, const char* payload)
{ {
char tmp_topic[strlen(mqttNodeTopic) + 20]; char tmp_topic[strlen(mqttNodeTopic) + 20];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/%s"), mqttNodeTopic, subtopic); snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%sstate/%s"), mqttNodeTopic, subtopic);
mqttPublish(tmp_topic, payload, false); return mqttPublish(tmp_topic, payload, false);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -173,8 +169,8 @@ static void mqtt_message_cb(char* topic, byte* payload, unsigned int length)
} else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic } else if(topic == strstr_P(topic, PSTR("homeassistant/status"))) { // HA discovery topic
if(mqttHAautodiscover && !strcasecmp_P((char*)payload, PSTR("online"))) { if(mqttHAautodiscover && !strcasecmp_P((char*)payload, PSTR("online"))) {
dispatch_current_state(); mqtt_ha_register_auto_discovery(); // auto-discovery first
mqtt_ha_register_auto_discovery(); dispatch_current_state(); // send the data
} }
return; return;

View File

@ -67,7 +67,7 @@ bool ethernetEvery5Seconds()
void ethernet_get_statusupdate(char* buffer, size_t len) void ethernet_get_statusupdate(char* buffer, size_t len)
{ {
snprintf_P(buffer, len, PSTR("\"eth\":\"%s\",\"link\":\"%d Mbps\",\"ip\":\"%s\","), snprintf_P(buffer, len, PSTR("\"eth\":\"%s\",\"link\":\"%d Mbps\",\"ip\":\"%s\","),
eth_connected ? F("ON") : F("OFF"), ETH.linkSpeed(), ETH.localIP().toString().c_str()); eth_connected ? F("on") : F("off"), ETH.linkSpeed(), ETH.localIP().toString().c_str());
} }
#endif #endif

View File

@ -106,7 +106,7 @@ void ethernet_get_statusupdate(char* buffer, size_t len)
#endif #endif
IPAddress ip = Ethernet.localIP(); IPAddress ip = Ethernet.localIP();
snprintf_P(buffer, len, PSTR("\"eth\":\"%s\",\"link\":%d,\"ip\":\"%d.%d.%d.%d\","), state ? F("ON") : F("OFF"), 10, snprintf_P(buffer, len, PSTR("\"eth\":\"%s\",\"link\":%d,\"ip\":\"%d.%d.%d.%d\","), state ? F("on") : F("off"), 10,
ip[0], ip[1], ip[2], ip[3]); ip[0], ip[1], ip[2], ip[3]);
} }
#endif #endif

View File

@ -362,7 +362,7 @@ static void wifiReconnect(void)
// https://github.com/espressif/arduino-esp32/issues/3438#issuecomment-721428310 // https://github.com/espressif/arduino-esp32/issues/3438#issuecomment-721428310
WiFi.disconnect(true); WiFi.disconnect(true);
WiFi.begin(wifiSsid, wifiPassword); WiFi.begin(wifiSsid, wifiPassword);
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); // WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); // causes 255.255.255.255 IP errors
WiFi.setHostname(haspDevice.get_hostname()); WiFi.setHostname(haspDevice.get_hostname());
#endif #endif
} }

View File

@ -1,10 +1,11 @@
# config.yaml # config.yaml
--- ---
name: Common test information name: Common test information
description: Connection information for MQTT Client description: Connection information for MQTT Client
variables: variables:
host: 10.4.0.5 host: homeassistant.local
username: hasp
password: hasp
port: 1883 port: 1883
plate: plate35 plate: plate35

View File

@ -13,6 +13,9 @@ paho-mqtt:
host: "{host}" host: "{host}"
port: !int "{port:d}" port: !int "{port:d}"
timeout: 3 timeout: 3
auth:
username: "{username}"
password: "{password}"
marks: marks:
- parametrize: - parametrize:

View File

@ -13,6 +13,9 @@ paho-mqtt: &mqtt_spec
host: "{host}" host: "{host}"
port: !int "{port:d}" port: !int "{port:d}"
timeout: 1 timeout: 1
auth:
username: "{username}"
password: "{password}"
stages: stages:
- name: Page 1 - name: Page 1

View File

@ -1,6 +1,5 @@
# test_page.tavern.yaml # test_page.tavern.yaml
--- ---
test_name: Page command test_name: Page command
includes: includes:
@ -14,6 +13,9 @@ paho-mqtt:
host: "{host}" host: "{host}"
port: !int "{port:d}" port: !int "{port:d}"
timeout: 3 timeout: 3
auth:
username: "{username}"
password: "{password}"
stages: stages:
- name: step 1 - Page test - name: step 1 - Page test
@ -46,7 +48,7 @@ stages:
- name: step 4 - Page test - name: step 4 - Page test
mqtt_publish: mqtt_publish:
topic: hasp/{plate}/command/json topic: hasp/{plate}/command/json
payload: "[\"page=1\"]" payload: '["page=1"]'
mqtt_response: mqtt_response:
topic: hasp/{plate}/state/page topic: hasp/{plate}/state/page
payload: "1" payload: "1"
@ -55,7 +57,7 @@ stages:
- name: step 5 - Page test - name: step 5 - Page test
mqtt_publish: mqtt_publish:
topic: hasp/{plate}/command/json topic: hasp/{plate}/command/json
payload: "[\"page 300\"]" payload: '["page 300"]'
mqtt_response: mqtt_response:
topic: hasp/{plate}/state/page topic: hasp/{plate}/state/page
payload: "1" payload: "1"
@ -110,7 +112,7 @@ stages:
payload: "wakeup" payload: "wakeup"
mqtt_response: mqtt_response:
topic: hasp/{plate}/state/idle topic: hasp/{plate}/state/idle
payload: "LONG" payload: "long"
timeout: 190 timeout: 190
delay_after: 0 delay_after: 0
@ -120,7 +122,7 @@ stages:
payload: "wakeup" payload: "wakeup"
mqtt_response: mqtt_response:
topic: hasp/{plate}/state/idle topic: hasp/{plate}/state/idle
payload: "SHORT" payload: "short"
timeout: 70 timeout: 70
delay_after: 0 delay_after: 0
@ -130,6 +132,6 @@ stages:
payload: "wakeup" payload: "wakeup"
mqtt_response: mqtt_response:
topic: hasp/{plate}/state/idle topic: hasp/{plate}/state/idle
payload: "OFF" payload: "off"
timeout: 1 timeout: 1
delay_after: 0 delay_after: 0

View File

@ -13,6 +13,9 @@ paho-mqtt:
host: "{host}" host: "{host}"
port: !int "{port:d}" port: !int "{port:d}"
timeout: 3 timeout: 3
auth:
username: "{username}"
password: "{password}"
marks: marks:
- parametrize: - parametrize:
@ -52,8 +55,30 @@ marks:
vals: vals:
- [1, 0, 120, 121, 122, 123, 0, 255, "I'm sorry.", "louie"] - [1, 0, 120, 121, 122, 123, 0, 255, "I'm sorry.", "louie"]
- [1, 0, -10, -10, 256, 257, 1, 64, "louie", " The cat stretched."] - [1, 0, -10, -10, 256, 257, 1, 64, "louie", " The cat stretched."]
- [0, 1, 1024, 1025, 1026, 1027, 5, 0, "The pipe began to rust while new.", ""] - [
- [0, 1, 80, 81, 82, 83, 32535, 192, "" ," Oak is strong and also gives shade."] 0,
1,
1024,
1025,
1026,
1027,
5,
0,
"The pipe began to rust while new.",
"",
]
- [
0,
1,
80,
81,
82,
83,
32535,
192,
"",
" Oak is strong and also gives shade.",
]
stages: stages:
- name: Page 1 - name: Page 1
@ -202,7 +227,7 @@ stages:
json: json:
radius: !int "{radius:d}" radius: !int "{radius:d}"
timeout: 1 timeout: 1
- name: Set value_str - name: Set value_str
mqtt_publish: mqtt_publish:
topic: "hasp/{plate}/command/p1b1.value_str" topic: "hasp/{plate}/command/p1b1.value_str"

View File

@ -1,6 +1,5 @@
# test_value_str.tavern.yaml # test_value_str.tavern.yaml
--- ---
test_name: Obj Standard Properties test_name: Obj Standard Properties
includes: includes:
@ -14,6 +13,9 @@ paho-mqtt:
host: "{host}" host: "{host}"
port: !int "{port:d}" port: !int "{port:d}"
timeout: 3 timeout: 3
auth:
username: "{username}"
password: "{password}"
marks: marks:
- parametrize: - parametrize:
@ -26,14 +28,14 @@ marks:
- 30 - 30
- 31 - 31
- 32 - 32
# - 33 # - 33
# - 40 # - 40
- 41 - 41
- 50 - 50
- 51 - 51
- 91 - 91
# - 90 # - 90
# - 1 # - 1
- 2 - 2
- 71 - 71
- 80 - 80
@ -93,7 +95,7 @@ stages:
x: 128 x: 128
y: 128 y: 128
delay_after: 0 delay_after: 0
- name: Set value_str - name: Set value_str
mqtt_publish: mqtt_publish:
topic: "hasp/{plate}/command/p[1].b[1].value_str" topic: "hasp/{plate}/command/p[1].b[1].value_str"

View File

@ -0,0 +1,33 @@
;***************************************************;
; HUZZAH32 ESP32 with Featherwing TFT 2.4" ;
; - HUZZAH32 esp32 board ;
; - ili9341 TFT Featherwing 2.4" ;
; - STMPE610 touch controller ;
;***************************************************;
[env:huzzah32-featherwing-24]
extends = esp32
board = featheresp32
build_flags =
${env.build_flags}
${esp32.build_flags}
;region -- TFT_eSPI build options ------------------------
${lcd.featherwing-24}
-D TFT_MISO=19
-D TFT_MOSI=18
-D TFT_SCLK=5
-D TFT_DC=33
-D TFT_CS=15
-D TFT_RST=-1 ; RST
-D TFT_BCKL=-1 ; Solder the LITE pad to a PWM enabled pin of the ESP.
-D STMPE_CS=32
;endregion
lib_deps =
${env.lib_deps}
${esp32.lib_deps}
lib_ignore =
${env.lib_ignore}
${esp32.lib_ignore}

View File

@ -0,0 +1,33 @@
;***************************************************;
; HUZZAH32 ESP32 with Featherwing TFT 3.5" ;
; - HUZZAH32 esp32 board ;
; - HX8357D TFT Featherwing 3.5" ;
; - STMPE610 touch controller ;
;***************************************************;
[env:huzzah32-featherwing-35]
extends = esp32
board = featheresp32
build_flags =
${env.build_flags}
${esp32.build_flags}
;region -- TFT_eSPI build options ------------------------
${lcd.featherwing-35}
-D TFT_MISO=19
-D TFT_MOSI=18
-D TFT_SCLK=5
-D TFT_DC=33
-D TFT_CS=15
-D TFT_RST=-1 ; RST
-D TFT_BCKL=-1 ; Solder the LITE pad to a PWM enabled pin of the ESP.
-D STMPE_CS=32
;endregion
lib_deps =
${env.lib_deps}
${esp32.lib_deps}
lib_ignore =
${env.lib_ignore}
${esp32.lib_ignore}

View File

@ -86,3 +86,27 @@ wt32-sc01 =
-D SPI_FREQUENCY=40000000 -D SPI_FREQUENCY=40000000
-D USER_SETUP_LOADED=1 -D USER_SETUP_LOADED=1
;-D SUPPORT_TRANSACTIONS ; Default on ESP32 ;-D SUPPORT_TRANSACTIONS ; Default on ESP32
featherwing-35 =
-D HX8357D_DRIVER=1
-D TFT_WIDTH=320
-D TFT_HEIGHT=480
-D TFT_ROTATION=0 ; Use default, see TFT_ROTATION values
-D SPI_FREQUENCY=27000000
-D SPI_TOUCH_FREQUENCY=2500000
-D SPI_READ_FREQUENCY=20000000
-D USER_SETUP_LOADED=1
-D TOUCH_DRIVER=610 ;STMPE610
;-D SUPPORT_TRANSACTIONS ; Default on ESP32
featherwing-24 =
-D ILI9341_DRIVER=1
-D TFT_WIDTH=240
-D TFT_HEIGHT=320
-D TFT_ROTATION=0 ; Use default, see TFT_ROTATION values
-D SPI_FREQUENCY=27000000
-D SPI_TOUCH_FREQUENCY=2500000
-D SPI_READ_FREQUENCY=20000000
-D USER_SETUP_LOADED=1
-D TOUCH_DRIVER=610 ;STMPE610
;-D SUPPORT_TRANSACTIONS ; Default on ESP32

View File

@ -82,7 +82,6 @@ lib_ignore =
paho paho
AXP192 AXP192
ArduinoLog ArduinoLog
lv_fs_if
src_filter = src_filter =
+<*> +<*>