The Pikachus of the Clock page are icons
Stored as icons at boot from the firmware's bitmaps (cut to 80 x 19), so they can be edited; the firmware copies stay the fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No files matched your search
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 371 KiB After Width: | Height: | Size: 346 KiB |
|
Before Width: | Height: | Size: 422 KiB After Width: | Height: | Size: 414 KiB |
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 196 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 370 KiB After Width: | Height: | Size: 367 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 131 KiB |
@@ -72,7 +72,7 @@ Start, stop and reset the stopwatch that pages can show (also in Home Assistant)
|
|||||||
## Bitmaps
|
## Bitmaps
|
||||||
|
|
||||||
All bitmaps with a preview: show one as the page, send it live, open it in the editor,
|
All bitmaps with a preview: show one as the page, send it live, open it in the editor,
|
||||||
export or delete it. The built-in ones (Nintendo, Pikachu, Pikachu yawning) can't be
|
export or delete it. The built-in one (Nintendo) can't be
|
||||||
deleted, nor can a bitmap that a page, the schedule or a rule uses. "Make icon" turns a
|
deleted, nor can a bitmap that a page, the schedule or a rule uses. "Make icon" turns a
|
||||||
bitmap that is only part of pages into an [icon](#icons).
|
bitmap that is only part of pages into an [icon](#icons).
|
||||||
|
|
||||||
@@ -85,7 +85,9 @@ element, or a background (drawn at the top left). Icons are never shown on their
|
|||||||
they are not in the page lists (Show, Schedule, rules, Home Assistant "Mode"). Each icon
|
they are not in the page lists (Show, Schedule, rules, Home Assistant "Mode"). Each icon
|
||||||
shows its size and the pages that use it. The editor: draw dots, change the size (the dots
|
shows its size and the pages that use it. The editor: draw dots, change the size (the dots
|
||||||
stay at the top left), crop to the dots, clear, invert, load an image (scaled to the icon
|
stay at the top left), crop to the dots, clear, invert, load an image (scaled to the icon
|
||||||
size), show it on the display. "Make bitmap" turns an icon into a full screen bitmap.
|
size), show it on the display. "Make bitmap" turns an icon into a full screen bitmap. The two Pikachus of the Clock page are built into the
|
||||||
|
firmware: they are stored as icons at boot and can be edited, the firmware keeps the
|
||||||
|
originals.
|
||||||
|
|
||||||
Firmware 2.10.0 made icons of all uploaded bitmaps that only pages used (backgrounds and
|
Firmware 2.10.0 made icons of all uploaded bitmaps that only pages used (backgrounds and
|
||||||
images, not shown by the schedule, a rule, the chosen page or the off image), once, after
|
images, not shown by the schedule, a rule, the chosen page or the off image), once, after
|
||||||
|
|||||||
@@ -423,6 +423,8 @@ const char *appBitmapToIcon(const char *name)
|
|||||||
|
|
||||||
const char *appIconToBitmap(const char *name)
|
const char *appIconToBitmap(const char *name)
|
||||||
{
|
{
|
||||||
|
if (builtinIconName(name))
|
||||||
|
return "Built-in icons stay icons (the firmware has them as icons)";
|
||||||
Icon icon;
|
Icon icon;
|
||||||
if (!loadIcon(name, icon))
|
if (!loadIcon(name, icon))
|
||||||
return "Icon not found";
|
return "Icon not found";
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ const uint32_t SETUP_AP_DELAY = 20000; // open the AP when WiFi fails thi
|
|||||||
const uint32_t WIFI_CONNECT_TIMEOUT = 30000;
|
const uint32_t WIFI_CONNECT_TIMEOUT = 30000;
|
||||||
const uint32_t WIFI_RESTART_TIME = 10UL * 60 * 1000;
|
const uint32_t WIFI_RESTART_TIME = 10UL * 60 * 1000;
|
||||||
|
|
||||||
#define FIRMWARE_VERSION "2.11.0"
|
#define FIRMWARE_VERSION "2.12.0"
|
||||||
|
|
||||||
// Home Assistant device id (do not change: Home Assistant's entities are linked to it)
|
// Home Assistant device id (do not change: Home Assistant's entities are linked to it)
|
||||||
const uint8_t HA_DEVICE_ID[] = {0x34, 0x86, 0x5d, 0x3a, 0x08, 0x28};
|
const uint8_t HA_DEVICE_ID[] = {0x34, 0x86, 0x5d, 0x3a, 0x08, 0x28};
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ struct BuiltinBitmap
|
|||||||
|
|
||||||
static const BuiltinBitmap BUILTIN[] = {
|
static const BuiltinBitmap BUILTIN[] = {
|
||||||
{"Nintendo", nintendo_bitmap_Nintendo_new},
|
{"Nintendo", nintendo_bitmap_Nintendo_new},
|
||||||
{"Pikachu", pikachu_clock_bitmap},
|
// The Pikachus of the Clock page are icons (display/icon_store)
|
||||||
{"Pikachu yawning", pikachu_yawning_clock_bitmap},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool mounted = false;
|
static bool mounted = false;
|
||||||
|
|||||||
@@ -6,11 +6,45 @@
|
|||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
|
||||||
#include "display/bitmap_store.h"
|
#include "display/bitmap_store.h"
|
||||||
|
#include "display/bitmaps.h"
|
||||||
|
|
||||||
static const char *DIR = "/icons";
|
static const char *DIR = "/icons";
|
||||||
// Written when the bitmaps were moved (not a valid name, so never listed)
|
// Written when the bitmaps were moved (not a valid name, so never listed)
|
||||||
static const char *MIGRATED = "/icons/.migrated";
|
static const char *MIGRATED = "/icons/.migrated";
|
||||||
|
|
||||||
|
// Built into the firmware (full screen bitmaps, cut to icons): stored at boot so they can
|
||||||
|
// be edited, and the fallback when they are not stored
|
||||||
|
struct BuiltinIcon
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
const uint8_t *bitmap; // PROGMEM, BITMAP_BYTES
|
||||||
|
};
|
||||||
|
static const BuiltinIcon BUILTIN[] = {
|
||||||
|
{"Pikachu", pikachu_clock_bitmap},
|
||||||
|
{"Pikachu yawning", pikachu_yawning_clock_bitmap},
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool builtinIcon(const char *name, Icon &icon)
|
||||||
|
{
|
||||||
|
for (const BuiltinIcon &b : BUILTIN)
|
||||||
|
if (strcasecmp(b.name, name) == 0)
|
||||||
|
{
|
||||||
|
uint8_t bitmap[BITMAP_BYTES];
|
||||||
|
memcpy_P(bitmap, b.bitmap, BITMAP_BYTES);
|
||||||
|
iconFromBitmap(bitmap, icon);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool builtinIconName(const char *name)
|
||||||
|
{
|
||||||
|
for (const BuiltinIcon &b : BUILTIN)
|
||||||
|
if (strcasecmp(b.name, name) == 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t revision = 0;
|
static uint32_t revision = 0;
|
||||||
// Counted once (listing the directory is slow), then kept up to date; -1: not yet
|
// Counted once (listing the directory is slow), then kept up to date; -1: not yet
|
||||||
static int count = -1;
|
static int count = -1;
|
||||||
@@ -37,9 +71,24 @@ static bool ensureDir()
|
|||||||
return LittleFS.exists(DIR) || LittleFS.mkdir(DIR);
|
return LittleFS.exists(DIR) || LittleFS.mkdir(DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iconStoreBegin()
|
||||||
|
{
|
||||||
|
for (const BuiltinIcon &b : BUILTIN)
|
||||||
|
{
|
||||||
|
Icon icon;
|
||||||
|
if (!bitmapStorageAvailable() || LittleFS.exists(path(b.name)) || !builtinIcon(b.name, icon))
|
||||||
|
continue;
|
||||||
|
const char *error = saveIcon(b.name, icon);
|
||||||
|
Serial.printf("Icon \"%s\" stored from the firmware: %s\n", b.name, error ? error : "ok");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<String> listIcons()
|
std::vector<String> listIcons()
|
||||||
{
|
{
|
||||||
std::vector<String> names = storedNames(DIR, ".bin");
|
std::vector<String> names = storedNames(DIR, ".bin");
|
||||||
|
for (const BuiltinIcon &b : BUILTIN) // not stored (no storage)
|
||||||
|
if (std::none_of(names.begin(), names.end(), [&b](const String &n) { return strcasecmp(n.c_str(), b.name) == 0; }))
|
||||||
|
names.push_back(b.name);
|
||||||
std::sort(names.begin(), names.end(),
|
std::sort(names.begin(), names.end(),
|
||||||
[](const String &a, const String &b) { return strcasecmp(a.c_str(), b.c_str()) < 0; });
|
[](const String &a, const String &b) { return strcasecmp(a.c_str(), b.c_str()) < 0; });
|
||||||
return names;
|
return names;
|
||||||
@@ -59,7 +108,7 @@ bool iconExists(const char *name)
|
|||||||
bool loadIcon(const char *name, Icon &icon)
|
bool loadIcon(const char *name, Icon &icon)
|
||||||
{
|
{
|
||||||
if (!bitmapStorageAvailable() || !validBitmapName(name))
|
if (!bitmapStorageAvailable() || !validBitmapName(name))
|
||||||
return false;
|
return builtinIcon(name, icon);
|
||||||
auto cached = cache.find(name);
|
auto cached = cache.find(name);
|
||||||
if (cached != cache.end())
|
if (cached != cache.end())
|
||||||
{
|
{
|
||||||
@@ -88,6 +137,8 @@ bool loadIcon(const char *name, Icon &icon)
|
|||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!ok)
|
||||||
|
ok = builtinIcon(name, loaded);
|
||||||
if (cache.size() >= CACHE_MAX)
|
if (cache.size() >= CACHE_MAX)
|
||||||
cache.clear();
|
cache.clear();
|
||||||
CachedIcon &entry = cache[name];
|
CachedIcon &entry = cache[name];
|
||||||
|
|||||||
@@ -12,6 +12,12 @@
|
|||||||
|
|
||||||
const int MAX_ICONS = 200;
|
const int MAX_ICONS = 200;
|
||||||
|
|
||||||
|
// At boot: stores the icons built into the firmware (the Pikachus of the Clock page) when
|
||||||
|
// they are not stored, so they can be edited. The built-in ones stay the fallback.
|
||||||
|
void iconStoreBegin();
|
||||||
|
// One of them (it always exists)
|
||||||
|
bool builtinIconName(const char *name);
|
||||||
|
|
||||||
// Sorted without case
|
// Sorted without case
|
||||||
std::vector<String> listIcons();
|
std::vector<String> listIcons();
|
||||||
// Changes each time an icon is saved or deleted
|
// Changes each time an icon is saved or deleted
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "display/bitmap_store.h"
|
#include "display/bitmap_store.h"
|
||||||
|
#include "display/icon_store.h"
|
||||||
#include "display/page_store.h"
|
#include "display/page_store.h"
|
||||||
#include "logic/status_led.h"
|
#include "logic/status_led.h"
|
||||||
#include "nano_link/nano_flash_bridge.h"
|
#include "nano_link/nano_flash_bridge.h"
|
||||||
@@ -34,6 +35,7 @@ void setup()
|
|||||||
BootMode boot_mode = firmwareGuardBegin();
|
BootMode boot_mode = firmwareGuardBegin();
|
||||||
|
|
||||||
bitmapStoreBegin();
|
bitmapStoreBegin();
|
||||||
|
iconStoreBegin(); // the Pikachus as icons that can be edited
|
||||||
pageStoreBegin(); // the Clock page as a page that can be edited
|
pageStoreBegin(); // the Clock page as a page that can be edited
|
||||||
appLoadSettings();
|
appLoadSettings();
|
||||||
|
|
||||||
|
|||||||