mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add qr code support for displays (#2952)
Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							ef832becf1
						
					
				
				
					commit
					a718ac7ee0
				
			| @@ -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 | ||||||
|   | |||||||
| @@ -33,10 +33,11 @@ build_flags = | |||||||
| ; This are common settings for all environments. | ; This are common settings for all environments. | ||||||
| [common] | [common] | ||||||
| lib_deps = | lib_deps = | ||||||
|     esphome/noise-c@0.1.4         ; api |     esphome/noise-c@0.1.4                  ; api | ||||||
|     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 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user