Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add UICamera #73

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ if get_option('front-lvgl').enabled()
'src/uicomponents/imgs/colortemp24.c',
'src/uicomponents/imgs/brightness24.c',
'src/uicomponents/imgs/white24.c',
'src/uicomponents/UICamera.cpp',
'src/uicomponents/uirgblight.cpp',
'src/uicomponents/UILogBox.cpp',
'src/uicomponents/UIComponents.cpp',
Expand Down
1 change: 1 addition & 0 deletions src/HAEntity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum class EntityType
Light,
Switch,
Fan,
Camera,
OTHER,
};

Expand Down
1 change: 1 addition & 0 deletions src/front-lvgl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ void uithread(HABackend& _backend, int _argc, char* _argv[])
{EntityType::Light, makeUIElement<UIRGBLight>},
{EntityType::Switch, makeUIElement<UISwitch>},
{EntityType::Fan, makeUIElement<UIButton>},
{EntityType::Camera, makeUIElement<UICamera>},
{EntityType::OTHER, makeUIElement<UIDummy>}};

auto entities = _backend.getEntitiesByPattern(entity_command.get<string>("pattern"));
Expand Down
3 changes: 3 additions & 0 deletions src/front-lvgl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
#include <src/core/lv_disp.h>
#include <utility>
#include "sdl/sdl.h"

// FIXME the includes for all the components should maybe be in uicomponents.hpp itself?
#include "uicomponents/UIComponents.hpp"
#include "uicomponents/uirgblight.hpp"
#include "uicomponents/UICamera.hpp"
#include <generated/domains.hpp>

using std::string;
Expand Down
10 changes: 5 additions & 5 deletions src/lv_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
*With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
*However the opened images might consume additional RAM.
*0: to disable caching*/
#define LV_IMG_CACHE_DEF_SIZE 0
#define LV_IMG_CACHE_DEF_SIZE 10

/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
Expand Down Expand Up @@ -609,9 +609,9 @@
/*File system interfaces for common APIs */

/*API for fopen, fread, etc*/
#define LV_USE_FS_STDIO 0
#define LV_USE_FS_STDIO 1
#if LV_USE_FS_STDIO
#define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
#define LV_FS_STDIO_LETTER 'A' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
#define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/
#define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
#endif
Expand Down Expand Up @@ -647,14 +647,14 @@
#endif

/*PNG decoder library*/
#define LV_USE_PNG 0
#define LV_USE_PNG 1

/*BMP decoder library*/
#define LV_USE_BMP 0

/* JPG + split JPG decoder library.
* Split JPG is a custom format optimized for embedded systems. */
#define LV_USE_SJPG 0
#define LV_USE_SJPG 1

/*GIF decoder library*/
#define LV_USE_GIF 0
Expand Down
141 changes: 141 additions & 0 deletions src/uicomponents/UICamera.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#include "UICamera.hpp"
#include "logger.hpp"
#include <src/widgets/lv_img.h>

// FIXME: we do a whole lot of json parsing in this file, that we should be doing somewhere else.

UICamera::UICamera(std::shared_ptr<HAEntity> _entity, lv_obj_t* _parent) :
UIEntity(_entity, _parent)
{
auto state = entity->getJsonState();
std::cerr << "INITIAL STATE FOR " << _entity->name << ":" << state.dump(2) << std::endl;

if (!state.contains("attributes")) {
throw std::runtime_error("Camera can't operate with a state that has no attributes");
}

auto attributes = state["attributes"];

// We generate a UI based on 'supported_color_modes'. color_mode then tells us which mode to use. Color_mode should be in update()
imgpanel = lv_img_create(_parent);
lv_img_set_src(imgpanel, "A:test.png");
// lv_obj_set_width(imgpanel, uiEntityWidth);
// lv_obj_set_height(imgpanel, 380);
lv_obj_set_style_pad_all(imgpanel, 5, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_align(imgpanel, LV_ALIGN_CENTER);
lv_obj_set_flex_flow(imgpanel, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(imgpanel, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START);


// lv_obj_align(imgpanel, LV_ALIGN_LEFT_MID, 20, 0);

update();
}

// code from https://curl.se/libcurl/c/getinmemory.html, modified

// FIXME: use std::array?
struct MemoryStruct {
char *memory;
size_t size;
};

static size_t
writeMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;

char *ptr = static_cast<char*>(realloc(mem->memory, mem->size + realsize + 1));
if(!ptr) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}

mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;

return realsize;
}

// end code from

void UICamera::update()
{
auto state = entity->getJsonState();
std::cerr << "UPDATED STATE FOR " << entity->name << ":" << state.dump(2) << std::endl;

{
std::unique_lock<std::mutex> lvlock(g_lvgl_updatelock);
auto url = "http://grace.7bits.nl:8123" + state["attributes"]["entity_picture"].get<string>();
g_log << "camera URL: " << url << std::endl;

// code from as above, modified
CURL *curl_handle;
CURLcode res;

struct MemoryStruct chunk;
chunk.memory = static_cast<char*>(malloc(1)); /* grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */

curl_global_init(CURL_GLOBAL_ALL);

/* init the curl session */
curl_handle = curl_easy_init();

/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());

/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, writeMemoryCallback);

/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

/* some servers do not like requests that are made without a user-agent
field, so we provide one */
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");

/* get it! */
res = curl_easy_perform(curl_handle);

/* check for errors */
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
else {
/*
* Now, our chunk.memory points to a memory block that is chunk.size
* bytes big and contains the remote file.
*
* Do something nice with it!
*/

printf("%lu bytes retrieved\n", (unsigned long)chunk.size);
}

/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
// end code from

img = {
.header = {
.cf = LV_IMG_CF_RAW_ALPHA,
.always_zero = 0,
.w = 0,
.h = 0,
},
};

img.data_size = chunk.size;
img.data = (uint8_t*)(chunk.memory);

lv_img_set_src(imgpanel, &img);

// free(chunk.memory); // FIXME this leaks terribly
}
}
17 changes: 17 additions & 0 deletions src/uicomponents/UICamera.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once
#include "UIComponents.hpp"
#include <src/core/lv_event.h>
#include <src/draw/lv_img_buf.h>

class UICamera : public UIEntity
{
public:
UICamera(std::shared_ptr<HAEntity> _entity, lv_obj_t* _parent);

void update() override;

private:
// FIXME: we never free() the lv_obj_t*'s in code
lv_obj_t* imgpanel;
lv_img_dsc_t img;
};
Loading