mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 17:54:13 +01:00
Add qr code support for displays (#2952)
Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
This commit is contained in:
parent
ef832becf1
commit
a718ac7ee0
10 changed files with 167 additions and 4 deletions
|
@ -137,6 +137,7 @@ esphome/components/preferences/* @esphome/core
|
||||||
esphome/components/psram/* @esphome/core
|
esphome/components/psram/* @esphome/core
|
||||||
esphome/components/pulse_meter/* @stevebaxter
|
esphome/components/pulse_meter/* @stevebaxter
|
||||||
esphome/components/pvvx_mithermometer/* @pasiz
|
esphome/components/pvvx_mithermometer/* @pasiz
|
||||||
|
esphome/components/qr_code/* @wjtje
|
||||||
esphome/components/rc522/* @glmnet
|
esphome/components/rc522/* @glmnet
|
||||||
esphome/components/rc522_i2c/* @glmnet
|
esphome/components/rc522_i2c/* @glmnet
|
||||||
esphome/components/rc522_spi/* @glmnet
|
esphome/components/rc522_spi/* @glmnet
|
||||||
|
|
|
@ -252,6 +252,12 @@ void DisplayBuffer::legend(int x, int y, graph::Graph *graph, Color color_on) {
|
||||||
}
|
}
|
||||||
#endif // USE_GRAPH
|
#endif // USE_GRAPH
|
||||||
|
|
||||||
|
#ifdef USE_QR_CODE
|
||||||
|
void DisplayBuffer::qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on, int scale) {
|
||||||
|
qr_code->draw(this, x, y, color_on, scale);
|
||||||
|
}
|
||||||
|
#endif // USE_QR_CODE
|
||||||
|
|
||||||
void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1,
|
void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1,
|
||||||
int *width, int *height) {
|
int *width, int *height) {
|
||||||
int x_offset, baseline;
|
int x_offset, baseline;
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
#include "esphome/components/graph/graph.h"
|
#include "esphome/components/graph/graph.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_QR_CODE
|
||||||
|
#include "esphome/components/qr_code/qr_code.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace display {
|
namespace display {
|
||||||
|
|
||||||
|
@ -307,6 +311,17 @@ class DisplayBuffer {
|
||||||
void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
|
void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
|
||||||
#endif // USE_GRAPH
|
#endif // USE_GRAPH
|
||||||
|
|
||||||
|
#ifdef USE_QR_CODE
|
||||||
|
/** Draw the `qr_code` with the top-left corner at [x,y] to the screen.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate of the upper left corner.
|
||||||
|
* @param y The y coordinate of the upper left corner.
|
||||||
|
* @param qr_code The qr_code to draw
|
||||||
|
* @param color_on The color to replace in binary images for the on bits.
|
||||||
|
*/
|
||||||
|
void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Get the text bounds of the given string.
|
/** Get the text bounds of the given string.
|
||||||
*
|
*
|
||||||
* @param x The x coordinate to place the string at, can be 0 if only interested in dimensions.
|
* @param x The x coordinate to place the string at, can be 0 if only interested in dimensions.
|
||||||
|
|
41
esphome/components/qr_code/__init__.py
Normal file
41
esphome/components/qr_code/__init__.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.const import CONF_ID, CONF_VALUE
|
||||||
|
|
||||||
|
CONF_SCALE = "scale"
|
||||||
|
CONF_ECC = "ecc"
|
||||||
|
|
||||||
|
CODEOWNERS = ["@wjtje"]
|
||||||
|
|
||||||
|
DEPENDENCIES = ["display"]
|
||||||
|
MULTI_CONF = True
|
||||||
|
|
||||||
|
qr_code_ns = cg.esphome_ns.namespace("qr_code")
|
||||||
|
QRCode = qr_code_ns.class_("QrCode", cg.Component)
|
||||||
|
|
||||||
|
qrcodegen_Ecc = cg.esphome_ns.enum("qrcodegen_Ecc")
|
||||||
|
ECC = {
|
||||||
|
"LOW": qrcodegen_Ecc.qrcodegen_Ecc_LOW,
|
||||||
|
"MEDIUM": qrcodegen_Ecc.qrcodegen_Ecc_MEDIUM,
|
||||||
|
"QUARTILE": qrcodegen_Ecc.qrcodegen_Ecc_QUARTILE,
|
||||||
|
"HIGH": qrcodegen_Ecc.qrcodegen_Ecc_HIGH,
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_ID): cv.declare_id(QRCode),
|
||||||
|
cv.Required(CONF_VALUE): cv.string,
|
||||||
|
cv.Optional(CONF_ECC, default="LOW"): cv.enum(ECC, upper=True),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
cg.add_library("wjtje/qr-code-generator-library", "^1.7.0")
|
||||||
|
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
cg.add(var.set_value(config[CONF_VALUE]))
|
||||||
|
cg.add(var.set_ecc(ECC[config[CONF_ECC]]))
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
cg.add_define("USE_QR_CODE")
|
55
esphome/components/qr_code/qr_code.cpp
Normal file
55
esphome/components/qr_code/qr_code.cpp
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include "qr_code.h"
|
||||||
|
#include "esphome/components/display/display_buffer.h"
|
||||||
|
#include "esphome/core/color.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace qr_code {
|
||||||
|
|
||||||
|
static const char *const TAG = "qr_code";
|
||||||
|
|
||||||
|
void QrCode::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "QR code:");
|
||||||
|
ESP_LOGCONFIG(TAG, " Value: '%s'", this->value_.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCode::set_value(const std::string &value) {
|
||||||
|
this->value_ = value;
|
||||||
|
this->needs_update_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCode::set_ecc(qrcodegen_Ecc ecc) {
|
||||||
|
this->ecc_ = ecc;
|
||||||
|
this->needs_update_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCode::generate_qr_code() {
|
||||||
|
ESP_LOGV(TAG, "Generating QR code...");
|
||||||
|
uint8_t tempbuffer[qrcodegen_BUFFER_LEN_MAX];
|
||||||
|
|
||||||
|
if (!qrcodegen_encodeText(this->value_.c_str(), tempbuffer, this->qr_, this->ecc_, qrcodegen_VERSION_MIN,
|
||||||
|
qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true)) {
|
||||||
|
ESP_LOGE(TAG, "Failed to generate QR code");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QrCode::draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale) {
|
||||||
|
ESP_LOGV(TAG, "Drawing QR code at (%d, %d)", x_offset, y_offset);
|
||||||
|
|
||||||
|
if (this->needs_update_) {
|
||||||
|
this->generate_qr_code();
|
||||||
|
this->needs_update_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t qrcode_width = qrcodegen_getSize(this->qr_);
|
||||||
|
|
||||||
|
for (int y = 0; y < qrcode_width * scale; y++) {
|
||||||
|
for (int x = 0; x < qrcode_width * scale; x++) {
|
||||||
|
if (qrcodegen_getModule(this->qr_, x / scale, y / scale)) {
|
||||||
|
buff->draw_pixel_at(x_offset + x, y_offset + y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace qr_code
|
||||||
|
} // namespace esphome
|
34
esphome/components/qr_code/qr_code.h
Normal file
34
esphome/components/qr_code/qr_code.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/color.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "qrcodegen.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
// forward declare DisplayBuffer
|
||||||
|
namespace display {
|
||||||
|
class DisplayBuffer;
|
||||||
|
} // namespace display
|
||||||
|
|
||||||
|
namespace qr_code {
|
||||||
|
class QrCode : public Component {
|
||||||
|
public:
|
||||||
|
void draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale);
|
||||||
|
|
||||||
|
void dump_config() override;
|
||||||
|
|
||||||
|
void set_value(const std::string &value);
|
||||||
|
void set_ecc(qrcodegen_Ecc ecc);
|
||||||
|
|
||||||
|
void generate_qr_code();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string value_;
|
||||||
|
qrcodegen_Ecc ecc_;
|
||||||
|
bool needs_update_ = true;
|
||||||
|
uint8_t qr_[qrcodegen_BUFFER_LEN_MAX];
|
||||||
|
};
|
||||||
|
} // namespace qr_code
|
||||||
|
} // namespace esphome
|
|
@ -32,6 +32,7 @@
|
||||||
#define USE_OTA_PASSWORD
|
#define USE_OTA_PASSWORD
|
||||||
#define USE_OTA_STATE_CALLBACK
|
#define USE_OTA_STATE_CALLBACK
|
||||||
#define USE_POWER_SUPPLY
|
#define USE_POWER_SUPPLY
|
||||||
|
#define USE_QR_CODE
|
||||||
#define USE_SELECT
|
#define USE_SELECT
|
||||||
#define USE_SENSOR
|
#define USE_SENSOR
|
||||||
#define USE_STATUS_LED
|
#define USE_STATUS_LED
|
||||||
|
|
|
@ -37,6 +37,7 @@ lib_deps =
|
||||||
makuna/NeoPixelBus@2.6.9 ; neopixelbus
|
makuna/NeoPixelBus@2.6.9 ; neopixelbus
|
||||||
esphome/Improv@1.1.0 ; improv_serial / esp32_improv
|
esphome/Improv@1.1.0 ; improv_serial / esp32_improv
|
||||||
bblanchon/ArduinoJson@6.18.5 ; json
|
bblanchon/ArduinoJson@6.18.5 ; json
|
||||||
|
wjtje/qr-code-generator-library@1.7.0 ; qr_code
|
||||||
build_flags =
|
build_flags =
|
||||||
-DESPHOME_LOG_LEVEL=ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
-DESPHOME_LOG_LEVEL=ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||||
src_filter =
|
src_filter =
|
||||||
|
|
|
@ -2154,6 +2154,7 @@ display:
|
||||||
pages:
|
pages:
|
||||||
- id: page1
|
- id: page1
|
||||||
lambda: |-
|
lambda: |-
|
||||||
|
it.qr_code(0, 0, id(homepage_qr));
|
||||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||||
- id: page2
|
- id: page2
|
||||||
lambda: |-
|
lambda: |-
|
||||||
|
@ -2577,3 +2578,7 @@ select:
|
||||||
- one
|
- one
|
||||||
- two
|
- two
|
||||||
optimistic: true
|
optimistic: true
|
||||||
|
|
||||||
|
qr_code:
|
||||||
|
- id: homepage_qr
|
||||||
|
value: https://esphome.io/index.html
|
||||||
|
|
|
@ -1351,6 +1351,10 @@ daly_bms:
|
||||||
update_interval: 20s
|
update_interval: 20s
|
||||||
uart_id: uart1
|
uart_id: uart1
|
||||||
|
|
||||||
|
qr_code:
|
||||||
|
- id: homepage_qr
|
||||||
|
value: https://esphome.io/index.html
|
||||||
|
|
||||||
button:
|
button:
|
||||||
- platform: output
|
- platform: output
|
||||||
id: output_button
|
id: output_button
|
||||||
|
|
Loading…
Reference in a new issue