mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[tm1651] Remove dependency on Arduino Library (#9645)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
This commit is contained in:
		| @@ -472,7 +472,7 @@ esphome/components/tlc5971/* @IJIJI | ||||
| esphome/components/tm1621/* @Philippe12 | ||||
| esphome/components/tm1637/* @glmnet | ||||
| esphome/components/tm1638/* @skykingjwc | ||||
| esphome/components/tm1651/* @freekode | ||||
| esphome/components/tm1651/* @mrtoy-me | ||||
| esphome/components/tmp102/* @timsavage | ||||
| esphome/components/tmp1075/* @sybrenstuvel | ||||
| esphome/components/tmp117/* @Azimath | ||||
|   | ||||
| @@ -10,26 +10,28 @@ from esphome.const import ( | ||||
|     CONF_LEVEL, | ||||
| ) | ||||
|  | ||||
| CODEOWNERS = ["@freekode"] | ||||
| CODEOWNERS = ["@mrtoy-me"] | ||||
|  | ||||
| CONF_LEVEL_PERCENT = "level_percent" | ||||
|  | ||||
| tm1651_ns = cg.esphome_ns.namespace("tm1651") | ||||
| TM1651Brightness = tm1651_ns.enum("TM1651Brightness") | ||||
| TM1651Display = tm1651_ns.class_("TM1651Display", cg.Component) | ||||
|  | ||||
| SetLevelPercentAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action) | ||||
| SetLevelAction = tm1651_ns.class_("SetLevelAction", automation.Action) | ||||
| SetBrightnessAction = tm1651_ns.class_("SetBrightnessAction", automation.Action) | ||||
| TurnOnAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action) | ||||
| TurnOffAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action) | ||||
|  | ||||
| CONF_LEVEL_PERCENT = "level_percent" | ||||
| SetLevelAction = tm1651_ns.class_("SetLevelAction", automation.Action) | ||||
| SetLevelPercentAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action) | ||||
| TurnOnAction = tm1651_ns.class_("TurnOnAction", automation.Action) | ||||
| TurnOffAction = tm1651_ns.class_("TurnOffAction", automation.Action) | ||||
|  | ||||
| TM1651_BRIGHTNESS_OPTIONS = { | ||||
|     1: TM1651Brightness.TM1651_BRIGHTNESS_LOW, | ||||
|     2: TM1651Brightness.TM1651_BRIGHTNESS_MEDIUM, | ||||
|     3: TM1651Brightness.TM1651_BRIGHTNESS_HIGH, | ||||
|     1: TM1651Brightness.TM1651_DARKEST, | ||||
|     2: TM1651Brightness.TM1651_TYPICAL, | ||||
|     3: TM1651Brightness.TM1651_BRIGHTEST, | ||||
| } | ||||
|  | ||||
| MULTI_CONF = True | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     cv.Schema( | ||||
|         { | ||||
| @@ -38,26 +40,21 @@ CONFIG_SCHEMA = cv.All( | ||||
|             cv.Required(CONF_DIO_PIN): pins.internal_gpio_output_pin_schema, | ||||
|         } | ||||
|     ), | ||||
|     cv.only_with_arduino, | ||||
| ) | ||||
|  | ||||
| validate_level_percent = cv.All(cv.int_range(min=0, max=100)) | ||||
| validate_level = cv.All(cv.int_range(min=0, max=7)) | ||||
| validate_brightness = cv.enum(TM1651_BRIGHTNESS_OPTIONS, int=True) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await cg.register_component(var, config) | ||||
|  | ||||
|     clk_pin = await cg.gpio_pin_expression(config[CONF_CLK_PIN]) | ||||
|     cg.add(var.set_clk_pin(clk_pin)) | ||||
|     dio_pin = await cg.gpio_pin_expression(config[CONF_DIO_PIN]) | ||||
|     cg.add(var.set_dio_pin(dio_pin)) | ||||
|  | ||||
|     # https://platformio.org/lib/show/6865/TM1651 | ||||
|     cg.add_library("freekode/TM1651", "1.0.1") | ||||
|  | ||||
| validate_brightness = cv.enum(TM1651_BRIGHTNESS_OPTIONS, int=True) | ||||
| validate_level = cv.All(cv.int_range(min=0, max=7)) | ||||
| validate_level_percent = cv.All(cv.int_range(min=0, max=100)) | ||||
|  | ||||
| BINARY_OUTPUT_ACTION_SCHEMA = maybe_simple_id( | ||||
|     { | ||||
| @@ -66,38 +63,22 @@ BINARY_OUTPUT_ACTION_SCHEMA = maybe_simple_id( | ||||
| ) | ||||
|  | ||||
|  | ||||
| @automation.register_action("tm1651.turn_on", TurnOnAction, BINARY_OUTPUT_ACTION_SCHEMA) | ||||
| async def output_turn_on_to_code(config, action_id, template_arg, args): | ||||
|     var = cg.new_Pvariable(action_id, template_arg) | ||||
|     await cg.register_parented(var, config[CONF_ID]) | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @automation.register_action( | ||||
|     "tm1651.turn_off", TurnOffAction, BINARY_OUTPUT_ACTION_SCHEMA | ||||
| ) | ||||
| async def output_turn_off_to_code(config, action_id, template_arg, args): | ||||
|     var = cg.new_Pvariable(action_id, template_arg) | ||||
|     await cg.register_parented(var, config[CONF_ID]) | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @automation.register_action( | ||||
|     "tm1651.set_level_percent", | ||||
|     SetLevelPercentAction, | ||||
|     "tm1651.set_brightness", | ||||
|     SetBrightnessAction, | ||||
|     cv.maybe_simple_value( | ||||
|         { | ||||
|             cv.GenerateID(): cv.use_id(TM1651Display), | ||||
|             cv.Required(CONF_LEVEL_PERCENT): cv.templatable(validate_level_percent), | ||||
|             cv.Required(CONF_BRIGHTNESS): cv.templatable(validate_brightness), | ||||
|         }, | ||||
|         key=CONF_LEVEL_PERCENT, | ||||
|         key=CONF_BRIGHTNESS, | ||||
|     ), | ||||
| ) | ||||
| async def tm1651_set_level_percent_to_code(config, action_id, template_arg, args): | ||||
| async def tm1651_set_brightness_to_code(config, action_id, template_arg, args): | ||||
|     var = cg.new_Pvariable(action_id, template_arg) | ||||
|     await cg.register_parented(var, config[CONF_ID]) | ||||
|     template_ = await cg.templatable(config[CONF_LEVEL_PERCENT], args, cg.uint8) | ||||
|     cg.add(var.set_level_percent(template_)) | ||||
|     template_ = await cg.templatable(config[CONF_BRIGHTNESS], args, cg.uint8) | ||||
|     cg.add(var.set_brightness(template_)) | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @@ -121,19 +102,35 @@ async def tm1651_set_level_to_code(config, action_id, template_arg, args): | ||||
|  | ||||
|  | ||||
| @automation.register_action( | ||||
|     "tm1651.set_brightness", | ||||
|     SetBrightnessAction, | ||||
|     "tm1651.set_level_percent", | ||||
|     SetLevelPercentAction, | ||||
|     cv.maybe_simple_value( | ||||
|         { | ||||
|             cv.GenerateID(): cv.use_id(TM1651Display), | ||||
|             cv.Required(CONF_BRIGHTNESS): cv.templatable(validate_brightness), | ||||
|             cv.Required(CONF_LEVEL_PERCENT): cv.templatable(validate_level_percent), | ||||
|         }, | ||||
|         key=CONF_BRIGHTNESS, | ||||
|         key=CONF_LEVEL_PERCENT, | ||||
|     ), | ||||
| ) | ||||
| async def tm1651_set_brightness_to_code(config, action_id, template_arg, args): | ||||
| async def tm1651_set_level_percent_to_code(config, action_id, template_arg, args): | ||||
|     var = cg.new_Pvariable(action_id, template_arg) | ||||
|     await cg.register_parented(var, config[CONF_ID]) | ||||
|     template_ = await cg.templatable(config[CONF_LEVEL_PERCENT], args, cg.uint8) | ||||
|     cg.add(var.set_level_percent(template_)) | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @automation.register_action( | ||||
|     "tm1651.turn_off", TurnOffAction, BINARY_OUTPUT_ACTION_SCHEMA | ||||
| ) | ||||
| async def output_turn_off_to_code(config, action_id, template_arg, args): | ||||
|     var = cg.new_Pvariable(action_id, template_arg) | ||||
|     await cg.register_parented(var, config[CONF_ID]) | ||||
|     return var | ||||
|  | ||||
|  | ||||
| @automation.register_action("tm1651.turn_on", TurnOnAction, BINARY_OUTPUT_ACTION_SCHEMA) | ||||
| async def output_turn_on_to_code(config, action_id, template_arg, args): | ||||
|     var = cg.new_Pvariable(action_id, template_arg) | ||||
|     await cg.register_parented(var, config[CONF_ID]) | ||||
|     template_ = await cg.templatable(config[CONF_BRIGHTNESS], args, cg.uint8) | ||||
|     cg.add(var.set_brightness(template_)) | ||||
|     return var | ||||
|   | ||||
| @@ -1,7 +1,54 @@ | ||||
| #ifdef USE_ARDUINO | ||||
| // This Esphome TM1651 component for use with Mini Battery Displays (7 LED levels) | ||||
| // and removes the Esphome dependency on the TM1651 Arduino library. | ||||
| // It was largely based on the work of others as set out below. | ||||
| // @mrtoy-me July 2025 | ||||
| // ============================================================================================== | ||||
| // Original Arduino TM1651 library: | ||||
| // Author:Fred.Chu | ||||
| // Date:14 August, 2014 | ||||
| // Applicable Module: Battery Display v1.0 | ||||
| // This library is free software; you can redistribute it and/or | ||||
| // modify it under the terms of the GNU Lesser General Public | ||||
| // License as published by the Free Software Foundation; either | ||||
| // version 2.1 of the License, or (at your option) any later version. | ||||
| // This library is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU | ||||
| // Lesser General Public License for more details. | ||||
| // Modified record: | ||||
| // Author:  Detlef Giessmann Germany | ||||
| // Mail:    mydiyp@web.de | ||||
| // Demo for the new 7 LED Battery-Display 2017 | ||||
| // IDE:     Arduino-1.6.5 | ||||
| // Type:    OPEN-SMART CX10*4RY68  4Color | ||||
| // Date:    01.05.2017 | ||||
| // ============================================================================================== | ||||
| // Esphome component using arduino TM1651 library: | ||||
| // MIT License | ||||
| // Copyright (c) 2019 freekode | ||||
| // ============================================================================================== | ||||
| // Library and command-line (python) program to control mini battery displays on Raspberry Pi: | ||||
| // MIT License | ||||
| // Copyright (c) 2020 Koen Vervloese | ||||
| // ============================================================================================== | ||||
| // MIT License | ||||
| // Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| // of this software and associated documentation files (the "Software"), to deal | ||||
| // in the Software without restriction, including without limitation the rights | ||||
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| // copies of the Software, and to permit persons to whom the Software is | ||||
| // furnished to do so, subject to the following conditions: | ||||
| // The above copyright notice and this permission notice shall be included in all | ||||
| // copies or substantial portions of the Software. | ||||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| // SOFTWARE. | ||||
|  | ||||
| #include "tm1651.h" | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| @@ -9,84 +56,205 @@ namespace tm1651 { | ||||
|  | ||||
| static const char *const TAG = "tm1651.display"; | ||||
|  | ||||
| static const uint8_t MAX_INPUT_LEVEL_PERCENT = 100; | ||||
| static const uint8_t TM1651_MAX_LEVEL = 7; | ||||
| static const bool LINE_HIGH = true; | ||||
| static const bool LINE_LOW = false; | ||||
|  | ||||
| static const uint8_t TM1651_BRIGHTNESS_LOW_HW = 0; | ||||
| static const uint8_t TM1651_BRIGHTNESS_MEDIUM_HW = 2; | ||||
| static const uint8_t TM1651_BRIGHTNESS_HIGH_HW = 7; | ||||
| // TM1651 maximum frequency is 500 kHz (duty ratio 50%) = 2 microseconds / cycle | ||||
| static const uint8_t CLOCK_CYCLE = 8; | ||||
|  | ||||
| static const uint8_t HALF_CLOCK_CYCLE = CLOCK_CYCLE / 2; | ||||
| static const uint8_t QUARTER_CLOCK_CYCLE = CLOCK_CYCLE / 4; | ||||
|  | ||||
| static const uint8_t ADDR_FIXED = 0x44;  // fixed address mode | ||||
| static const uint8_t ADDR_START = 0xC0;  // address of the display register | ||||
|  | ||||
| static const uint8_t DISPLAY_OFF = 0x80; | ||||
| static const uint8_t DISPLAY_ON = 0x88; | ||||
|  | ||||
| static const uint8_t MAX_DISPLAY_LEVELS = 7; | ||||
|  | ||||
| static const uint8_t PERCENT100 = 100; | ||||
| static const uint8_t PERCENT50 = 50; | ||||
|  | ||||
| static const uint8_t TM1651_BRIGHTNESS_DARKEST = 0; | ||||
| static const uint8_t TM1651_BRIGHTNESS_TYPICAL = 2; | ||||
| static const uint8_t TM1651_BRIGHTNESS_BRIGHTEST = 7; | ||||
|  | ||||
| static const uint8_t TM1651_LEVEL_TAB[] = {0b00000000, 0b00000001, 0b00000011, 0b00000111, | ||||
|                                            0b00001111, 0b00011111, 0b00111111, 0b01111111}; | ||||
|  | ||||
| // public | ||||
|  | ||||
| void TM1651Display::setup() { | ||||
|   uint8_t clk = clk_pin_->get_pin(); | ||||
|   uint8_t dio = dio_pin_->get_pin(); | ||||
|   this->clk_pin_->setup(); | ||||
|   this->clk_pin_->pin_mode(gpio::FLAG_OUTPUT); | ||||
|  | ||||
|   battery_display_ = make_unique<TM1651>(clk, dio); | ||||
|   battery_display_->init(); | ||||
|   battery_display_->clearDisplay(); | ||||
|   this->dio_pin_->setup(); | ||||
|   this->dio_pin_->pin_mode(gpio::FLAG_OUTPUT); | ||||
|  | ||||
|   this->brightness_ = TM1651_BRIGHTNESS_TYPICAL; | ||||
|  | ||||
|   // clear display | ||||
|   this->display_level_(); | ||||
|   this->update_brightness_(DISPLAY_ON); | ||||
| } | ||||
|  | ||||
| void TM1651Display::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "TM1651 Battery Display"); | ||||
|   ESP_LOGCONFIG(TAG, "Battery Display"); | ||||
|   LOG_PIN("  CLK: ", clk_pin_); | ||||
|   LOG_PIN("  DIO: ", dio_pin_); | ||||
| } | ||||
|  | ||||
| void TM1651Display::set_level_percent(uint8_t new_level) { | ||||
|   this->level_ = calculate_level_(new_level); | ||||
|   this->repaint_(); | ||||
| void TM1651Display::set_brightness(uint8_t new_brightness) { | ||||
|   this->brightness_ = this->remap_brightness_(new_brightness); | ||||
|   if (this->display_on_) { | ||||
|     this->update_brightness_(DISPLAY_ON); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void TM1651Display::set_level(uint8_t new_level) { | ||||
|   if (new_level > MAX_DISPLAY_LEVELS) | ||||
|     new_level = MAX_DISPLAY_LEVELS; | ||||
|   this->level_ = new_level; | ||||
|   this->repaint_(); | ||||
|   if (this->display_on_) { | ||||
|     this->display_level_(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void TM1651Display::set_brightness(uint8_t new_brightness) { | ||||
|   this->brightness_ = calculate_brightness_(new_brightness); | ||||
|   this->repaint_(); | ||||
| } | ||||
|  | ||||
| void TM1651Display::turn_on() { | ||||
|   this->is_on_ = true; | ||||
|   this->repaint_(); | ||||
| void TM1651Display::set_level_percent(uint8_t percentage) { | ||||
|   this->level_ = this->calculate_level_(percentage); | ||||
|   if (this->display_on_) { | ||||
|     this->display_level_(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void TM1651Display::turn_off() { | ||||
|   this->is_on_ = false; | ||||
|   battery_display_->displayLevel(0); | ||||
|   this->display_on_ = false; | ||||
|   this->update_brightness_(DISPLAY_OFF); | ||||
| } | ||||
|  | ||||
| void TM1651Display::repaint_() { | ||||
|   if (!this->is_on_) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   battery_display_->set(this->brightness_); | ||||
|   battery_display_->displayLevel(this->level_); | ||||
| void TM1651Display::turn_on() { | ||||
|   this->display_on_ = true; | ||||
|   // display level as it could have been changed when display turned off | ||||
|   this->display_level_(); | ||||
|   this->update_brightness_(DISPLAY_ON); | ||||
| } | ||||
|  | ||||
| uint8_t TM1651Display::calculate_level_(uint8_t new_level) { | ||||
|   if (new_level == 0) { | ||||
|     return 0; | ||||
|   } | ||||
| // protected | ||||
|  | ||||
|   float calculated_level = TM1651_MAX_LEVEL / (float) (MAX_INPUT_LEVEL_PERCENT / (float) new_level); | ||||
|   return (uint8_t) roundf(calculated_level); | ||||
| uint8_t TM1651Display::calculate_level_(uint8_t percentage) { | ||||
|   if (percentage > PERCENT100) | ||||
|     percentage = PERCENT100; | ||||
|   // scale 0-100% to 0-7 display levels | ||||
|   // use integer arithmetic with rounding | ||||
|   uint16_t initial_scaling = (percentage * MAX_DISPLAY_LEVELS) + PERCENT50; | ||||
|   return (uint8_t) (initial_scaling / PERCENT100); | ||||
| } | ||||
|  | ||||
| uint8_t TM1651Display::calculate_brightness_(uint8_t new_brightness) { | ||||
|   if (new_brightness <= 1) { | ||||
|     return TM1651_BRIGHTNESS_LOW_HW; | ||||
|   } else if (new_brightness == 2) { | ||||
|     return TM1651_BRIGHTNESS_MEDIUM_HW; | ||||
|   } else if (new_brightness >= 3) { | ||||
|     return TM1651_BRIGHTNESS_HIGH_HW; | ||||
| void TM1651Display::display_level_() { | ||||
|   this->start_(); | ||||
|   this->write_byte_(ADDR_FIXED); | ||||
|   this->stop_(); | ||||
|  | ||||
|   this->start_(); | ||||
|   this->write_byte_(ADDR_START); | ||||
|   this->write_byte_(TM1651_LEVEL_TAB[this->level_]); | ||||
|   this->stop_(); | ||||
| } | ||||
|  | ||||
| uint8_t TM1651Display::remap_brightness_(uint8_t new_brightness) { | ||||
|   if (new_brightness <= 1) | ||||
|     return TM1651_BRIGHTNESS_DARKEST; | ||||
|   if (new_brightness == 2) | ||||
|     return TM1651_BRIGHTNESS_TYPICAL; | ||||
|  | ||||
|   // new_brightness >= 3 | ||||
|   return TM1651_BRIGHTNESS_BRIGHTEST; | ||||
| } | ||||
|  | ||||
| void TM1651Display::update_brightness_(uint8_t on_off_control) { | ||||
|   this->start_(); | ||||
|   this->write_byte_(on_off_control | this->brightness_); | ||||
|   this->stop_(); | ||||
| } | ||||
|  | ||||
| // low level functions | ||||
|  | ||||
| bool TM1651Display::write_byte_(uint8_t data) { | ||||
|   // data bit written to DIO when CLK is low | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     this->half_cycle_clock_low_((bool) (data & 0x01)); | ||||
|     this->half_cycle_clock_high_(); | ||||
|     data >>= 1; | ||||
|   } | ||||
|  | ||||
|   return TM1651_BRIGHTNESS_LOW_HW; | ||||
|   // start 9th cycle, setting DIO high and look for ack | ||||
|   this->half_cycle_clock_low_(LINE_HIGH); | ||||
|   return this->half_cycle_clock_high_ack_(); | ||||
| } | ||||
|  | ||||
| void TM1651Display::half_cycle_clock_low_(bool data_bit) { | ||||
|   // first half cycle, clock low and write data bit | ||||
|   this->clk_pin_->digital_write(LINE_LOW); | ||||
|   delayMicroseconds(QUARTER_CLOCK_CYCLE); | ||||
|  | ||||
|   this->dio_pin_->digital_write(data_bit); | ||||
|   delayMicroseconds(QUARTER_CLOCK_CYCLE); | ||||
| } | ||||
|  | ||||
| void TM1651Display::half_cycle_clock_high_() { | ||||
|   // second half cycle, clock high | ||||
|   this->clk_pin_->digital_write(LINE_HIGH); | ||||
|   delayMicroseconds(HALF_CLOCK_CYCLE); | ||||
| } | ||||
|  | ||||
| bool TM1651Display::half_cycle_clock_high_ack_() { | ||||
|   // second half cycle, clock high and check for ack | ||||
|   this->clk_pin_->digital_write(LINE_HIGH); | ||||
|   delayMicroseconds(QUARTER_CLOCK_CYCLE); | ||||
|  | ||||
|   this->dio_pin_->pin_mode(gpio::FLAG_INPUT); | ||||
|   // valid ack on DIO is low | ||||
|   bool ack = (!this->dio_pin_->digital_read()); | ||||
|  | ||||
|   this->dio_pin_->pin_mode(gpio::FLAG_OUTPUT); | ||||
|  | ||||
|   // ack should be set DIO low by now | ||||
|   // if its not, set DIO low before the next cycle | ||||
|   if (!ack) { | ||||
|     this->dio_pin_->digital_write(LINE_LOW); | ||||
|   } | ||||
|   delayMicroseconds(QUARTER_CLOCK_CYCLE); | ||||
|  | ||||
|   // begin next cycle | ||||
|   this->clk_pin_->digital_write(LINE_LOW); | ||||
|  | ||||
|   return ack; | ||||
| } | ||||
|  | ||||
| void TM1651Display::start_() { | ||||
|   // start data transmission | ||||
|   this->delineate_transmission_(LINE_HIGH); | ||||
| } | ||||
|  | ||||
| void TM1651Display::stop_() { | ||||
|   // stop data transmission | ||||
|   this->delineate_transmission_(LINE_LOW); | ||||
| } | ||||
|  | ||||
| void TM1651Display::delineate_transmission_(bool dio_state) { | ||||
|   // delineate data transmission | ||||
|   // DIO changes its value while CLK is high | ||||
|  | ||||
|   this->dio_pin_->digital_write(dio_state); | ||||
|   delayMicroseconds(HALF_CLOCK_CYCLE); | ||||
|  | ||||
|   this->clk_pin_->digital_write(LINE_HIGH); | ||||
|   delayMicroseconds(QUARTER_CLOCK_CYCLE); | ||||
|  | ||||
|   this->dio_pin_->digital_write(!dio_state); | ||||
|   delayMicroseconds(QUARTER_CLOCK_CYCLE); | ||||
| } | ||||
|  | ||||
| }  // namespace tm1651 | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif  // USE_ARDUINO | ||||
|   | ||||
| @@ -1,22 +1,16 @@ | ||||
| #pragma once | ||||
|  | ||||
| #ifdef USE_ARDUINO | ||||
|  | ||||
| #include <memory> | ||||
|  | ||||
| #include "esphome/core/automation.h" | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/hal.h" | ||||
| #include "esphome/core/automation.h" | ||||
|  | ||||
| #include <TM1651.h> | ||||
|  | ||||
| namespace esphome { | ||||
| namespace tm1651 { | ||||
|  | ||||
| enum TM1651Brightness : uint8_t { | ||||
|   TM1651_BRIGHTNESS_LOW = 1, | ||||
|   TM1651_BRIGHTNESS_MEDIUM = 2, | ||||
|   TM1651_BRIGHTNESS_HIGH = 3, | ||||
|   TM1651_DARKEST = 1, | ||||
|   TM1651_TYPICAL = 2, | ||||
|   TM1651_BRIGHTEST = 3, | ||||
| }; | ||||
|  | ||||
| class TM1651Display : public Component { | ||||
| @@ -27,36 +21,49 @@ class TM1651Display : public Component { | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void set_level_percent(uint8_t new_level); | ||||
|   void set_level(uint8_t new_level); | ||||
|   void set_brightness(uint8_t new_brightness); | ||||
|   void set_brightness(TM1651Brightness new_brightness) { this->set_brightness(static_cast<uint8_t>(new_brightness)); } | ||||
|  | ||||
|   void turn_on(); | ||||
|   void set_level(uint8_t new_level); | ||||
|   void set_level_percent(uint8_t percentage); | ||||
|  | ||||
|   void turn_off(); | ||||
|   void turn_on(); | ||||
|  | ||||
|  protected: | ||||
|   std::unique_ptr<TM1651> battery_display_; | ||||
|   uint8_t calculate_level_(uint8_t percentage); | ||||
|   void display_level_(); | ||||
|  | ||||
|   uint8_t remap_brightness_(uint8_t new_brightness); | ||||
|   void update_brightness_(uint8_t on_off_control); | ||||
|  | ||||
|   // low level functions | ||||
|   bool write_byte_(uint8_t data); | ||||
|  | ||||
|   void half_cycle_clock_low_(bool data_bit); | ||||
|   void half_cycle_clock_high_(); | ||||
|   bool half_cycle_clock_high_ack_(); | ||||
|  | ||||
|   void start_(); | ||||
|   void stop_(); | ||||
|  | ||||
|   void delineate_transmission_(bool dio_state); | ||||
|  | ||||
|   InternalGPIOPin *clk_pin_; | ||||
|   InternalGPIOPin *dio_pin_; | ||||
|   bool is_on_ = true; | ||||
|  | ||||
|   uint8_t brightness_; | ||||
|   uint8_t level_; | ||||
|  | ||||
|   void repaint_(); | ||||
|  | ||||
|   uint8_t calculate_level_(uint8_t new_level); | ||||
|   uint8_t calculate_brightness_(uint8_t new_brightness); | ||||
|   bool display_on_{true}; | ||||
|   uint8_t brightness_{}; | ||||
|   uint8_t level_{0}; | ||||
| }; | ||||
|  | ||||
| template<typename... Ts> class SetLevelPercentAction : public Action<Ts...>, public Parented<TM1651Display> { | ||||
| template<typename... Ts> class SetBrightnessAction : public Action<Ts...>, public Parented<TM1651Display> { | ||||
|  public: | ||||
|   TEMPLATABLE_VALUE(uint8_t, level_percent) | ||||
|   TEMPLATABLE_VALUE(uint8_t, brightness) | ||||
|  | ||||
|   void play(Ts... x) override { | ||||
|     auto level_percent = this->level_percent_.value(x...); | ||||
|     this->parent_->set_level_percent(level_percent); | ||||
|     auto brightness = this->brightness_.value(x...); | ||||
|     this->parent_->set_brightness(brightness); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| @@ -70,13 +77,13 @@ template<typename... Ts> class SetLevelAction : public Action<Ts...>, public Par | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template<typename... Ts> class SetBrightnessAction : public Action<Ts...>, public Parented<TM1651Display> { | ||||
| template<typename... Ts> class SetLevelPercentAction : public Action<Ts...>, public Parented<TM1651Display> { | ||||
|  public: | ||||
|   TEMPLATABLE_VALUE(uint8_t, brightness) | ||||
|   TEMPLATABLE_VALUE(uint8_t, level_percent) | ||||
|  | ||||
|   void play(Ts... x) override { | ||||
|     auto brightness = this->brightness_.value(x...); | ||||
|     this->parent_->set_brightness(brightness); | ||||
|     auto level_percent = this->level_percent_.value(x...); | ||||
|     this->parent_->set_level_percent(level_percent); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| @@ -92,5 +99,3 @@ template<typename... Ts> class TurnOffAction : public Action<Ts...>, public Pare | ||||
|  | ||||
| }  // namespace tm1651 | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif  // USE_ARDUINO | ||||
|   | ||||
							
								
								
									
										1
									
								
								tests/components/tm1651/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/tm1651/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										1
									
								
								tests/components/tm1651/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/components/tm1651/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| <<: !include common.yaml | ||||
		Reference in New Issue
	
	Block a user