mirror of
https://github.com/esphome/esphome.git
synced 2025-08-02 08:27:47 +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:
parent
f25abc3248
commit
88d8cfe6a2
@ -472,7 +472,7 @@ esphome/components/tlc5971/* @IJIJI
|
|||||||
esphome/components/tm1621/* @Philippe12
|
esphome/components/tm1621/* @Philippe12
|
||||||
esphome/components/tm1637/* @glmnet
|
esphome/components/tm1637/* @glmnet
|
||||||
esphome/components/tm1638/* @skykingjwc
|
esphome/components/tm1638/* @skykingjwc
|
||||||
esphome/components/tm1651/* @freekode
|
esphome/components/tm1651/* @mrtoy-me
|
||||||
esphome/components/tmp102/* @timsavage
|
esphome/components/tmp102/* @timsavage
|
||||||
esphome/components/tmp1075/* @sybrenstuvel
|
esphome/components/tmp1075/* @sybrenstuvel
|
||||||
esphome/components/tmp117/* @Azimath
|
esphome/components/tmp117/* @Azimath
|
||||||
|
@ -10,26 +10,28 @@ from esphome.const import (
|
|||||||
CONF_LEVEL,
|
CONF_LEVEL,
|
||||||
)
|
)
|
||||||
|
|
||||||
CODEOWNERS = ["@freekode"]
|
CODEOWNERS = ["@mrtoy-me"]
|
||||||
|
|
||||||
|
CONF_LEVEL_PERCENT = "level_percent"
|
||||||
|
|
||||||
tm1651_ns = cg.esphome_ns.namespace("tm1651")
|
tm1651_ns = cg.esphome_ns.namespace("tm1651")
|
||||||
TM1651Brightness = tm1651_ns.enum("TM1651Brightness")
|
TM1651Brightness = tm1651_ns.enum("TM1651Brightness")
|
||||||
TM1651Display = tm1651_ns.class_("TM1651Display", cg.Component)
|
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)
|
SetBrightnessAction = tm1651_ns.class_("SetBrightnessAction", automation.Action)
|
||||||
TurnOnAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
SetLevelAction = tm1651_ns.class_("SetLevelAction", automation.Action)
|
||||||
TurnOffAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
SetLevelPercentAction = tm1651_ns.class_("SetLevelPercentAction", automation.Action)
|
||||||
|
TurnOnAction = tm1651_ns.class_("TurnOnAction", automation.Action)
|
||||||
CONF_LEVEL_PERCENT = "level_percent"
|
TurnOffAction = tm1651_ns.class_("TurnOffAction", automation.Action)
|
||||||
|
|
||||||
TM1651_BRIGHTNESS_OPTIONS = {
|
TM1651_BRIGHTNESS_OPTIONS = {
|
||||||
1: TM1651Brightness.TM1651_BRIGHTNESS_LOW,
|
1: TM1651Brightness.TM1651_DARKEST,
|
||||||
2: TM1651Brightness.TM1651_BRIGHTNESS_MEDIUM,
|
2: TM1651Brightness.TM1651_TYPICAL,
|
||||||
3: TM1651Brightness.TM1651_BRIGHTNESS_HIGH,
|
3: TM1651Brightness.TM1651_BRIGHTEST,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MULTI_CONF = True
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
cv.Schema(
|
cv.Schema(
|
||||||
{
|
{
|
||||||
@ -38,26 +40,21 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
cv.Required(CONF_DIO_PIN): pins.internal_gpio_output_pin_schema,
|
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):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
clk_pin = await cg.gpio_pin_expression(config[CONF_CLK_PIN])
|
clk_pin = await cg.gpio_pin_expression(config[CONF_CLK_PIN])
|
||||||
cg.add(var.set_clk_pin(clk_pin))
|
cg.add(var.set_clk_pin(clk_pin))
|
||||||
dio_pin = await cg.gpio_pin_expression(config[CONF_DIO_PIN])
|
dio_pin = await cg.gpio_pin_expression(config[CONF_DIO_PIN])
|
||||||
cg.add(var.set_dio_pin(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(
|
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(
|
@automation.register_action(
|
||||||
"tm1651.turn_off", TurnOffAction, BINARY_OUTPUT_ACTION_SCHEMA
|
"tm1651.set_brightness",
|
||||||
)
|
SetBrightnessAction,
|
||||||
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,
|
|
||||||
cv.maybe_simple_value(
|
cv.maybe_simple_value(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.use_id(TM1651Display),
|
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)
|
var = cg.new_Pvariable(action_id, template_arg)
|
||||||
await cg.register_parented(var, config[CONF_ID])
|
await cg.register_parented(var, config[CONF_ID])
|
||||||
template_ = await cg.templatable(config[CONF_LEVEL_PERCENT], args, cg.uint8)
|
template_ = await cg.templatable(config[CONF_BRIGHTNESS], args, cg.uint8)
|
||||||
cg.add(var.set_level_percent(template_))
|
cg.add(var.set_brightness(template_))
|
||||||
return var
|
return var
|
||||||
|
|
||||||
|
|
||||||
@ -121,19 +102,35 @@ async def tm1651_set_level_to_code(config, action_id, template_arg, args):
|
|||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"tm1651.set_brightness",
|
"tm1651.set_level_percent",
|
||||||
SetBrightnessAction,
|
SetLevelPercentAction,
|
||||||
cv.maybe_simple_value(
|
cv.maybe_simple_value(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.use_id(TM1651Display),
|
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)
|
var = cg.new_Pvariable(action_id, template_arg)
|
||||||
await cg.register_parented(var, config[CONF_ID])
|
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
|
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 "tm1651.h"
|
||||||
#include "esphome/core/helpers.h"
|
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@ -9,84 +56,205 @@ namespace tm1651 {
|
|||||||
|
|
||||||
static const char *const TAG = "tm1651.display";
|
static const char *const TAG = "tm1651.display";
|
||||||
|
|
||||||
static const uint8_t MAX_INPUT_LEVEL_PERCENT = 100;
|
static const bool LINE_HIGH = true;
|
||||||
static const uint8_t TM1651_MAX_LEVEL = 7;
|
static const bool LINE_LOW = false;
|
||||||
|
|
||||||
static const uint8_t TM1651_BRIGHTNESS_LOW_HW = 0;
|
// TM1651 maximum frequency is 500 kHz (duty ratio 50%) = 2 microseconds / cycle
|
||||||
static const uint8_t TM1651_BRIGHTNESS_MEDIUM_HW = 2;
|
static const uint8_t CLOCK_CYCLE = 8;
|
||||||
static const uint8_t TM1651_BRIGHTNESS_HIGH_HW = 7;
|
|
||||||
|
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() {
|
void TM1651Display::setup() {
|
||||||
uint8_t clk = clk_pin_->get_pin();
|
this->clk_pin_->setup();
|
||||||
uint8_t dio = dio_pin_->get_pin();
|
this->clk_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
|
||||||
battery_display_ = make_unique<TM1651>(clk, dio);
|
this->dio_pin_->setup();
|
||||||
battery_display_->init();
|
this->dio_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
battery_display_->clearDisplay();
|
|
||||||
|
this->brightness_ = TM1651_BRIGHTNESS_TYPICAL;
|
||||||
|
|
||||||
|
// clear display
|
||||||
|
this->display_level_();
|
||||||
|
this->update_brightness_(DISPLAY_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TM1651Display::dump_config() {
|
void TM1651Display::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "TM1651 Battery Display");
|
ESP_LOGCONFIG(TAG, "Battery Display");
|
||||||
LOG_PIN(" CLK: ", clk_pin_);
|
LOG_PIN(" CLK: ", clk_pin_);
|
||||||
LOG_PIN(" DIO: ", dio_pin_);
|
LOG_PIN(" DIO: ", dio_pin_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TM1651Display::set_level_percent(uint8_t new_level) {
|
void TM1651Display::set_brightness(uint8_t new_brightness) {
|
||||||
this->level_ = calculate_level_(new_level);
|
this->brightness_ = this->remap_brightness_(new_brightness);
|
||||||
this->repaint_();
|
if (this->display_on_) {
|
||||||
|
this->update_brightness_(DISPLAY_ON);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TM1651Display::set_level(uint8_t new_level) {
|
void TM1651Display::set_level(uint8_t new_level) {
|
||||||
|
if (new_level > MAX_DISPLAY_LEVELS)
|
||||||
|
new_level = MAX_DISPLAY_LEVELS;
|
||||||
this->level_ = new_level;
|
this->level_ = new_level;
|
||||||
this->repaint_();
|
if (this->display_on_) {
|
||||||
|
this->display_level_();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TM1651Display::set_brightness(uint8_t new_brightness) {
|
void TM1651Display::set_level_percent(uint8_t percentage) {
|
||||||
this->brightness_ = calculate_brightness_(new_brightness);
|
this->level_ = this->calculate_level_(percentage);
|
||||||
this->repaint_();
|
if (this->display_on_) {
|
||||||
}
|
this->display_level_();
|
||||||
|
}
|
||||||
void TM1651Display::turn_on() {
|
|
||||||
this->is_on_ = true;
|
|
||||||
this->repaint_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TM1651Display::turn_off() {
|
void TM1651Display::turn_off() {
|
||||||
this->is_on_ = false;
|
this->display_on_ = false;
|
||||||
battery_display_->displayLevel(0);
|
this->update_brightness_(DISPLAY_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TM1651Display::repaint_() {
|
void TM1651Display::turn_on() {
|
||||||
if (!this->is_on_) {
|
this->display_on_ = true;
|
||||||
return;
|
// display level as it could have been changed when display turned off
|
||||||
}
|
this->display_level_();
|
||||||
|
this->update_brightness_(DISPLAY_ON);
|
||||||
battery_display_->set(this->brightness_);
|
|
||||||
battery_display_->displayLevel(this->level_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t TM1651Display::calculate_level_(uint8_t new_level) {
|
// protected
|
||||||
if (new_level == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float calculated_level = TM1651_MAX_LEVEL / (float) (MAX_INPUT_LEVEL_PERCENT / (float) new_level);
|
uint8_t TM1651Display::calculate_level_(uint8_t percentage) {
|
||||||
return (uint8_t) roundf(calculated_level);
|
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) {
|
void TM1651Display::display_level_() {
|
||||||
if (new_brightness <= 1) {
|
this->start_();
|
||||||
return TM1651_BRIGHTNESS_LOW_HW;
|
this->write_byte_(ADDR_FIXED);
|
||||||
} else if (new_brightness == 2) {
|
this->stop_();
|
||||||
return TM1651_BRIGHTNESS_MEDIUM_HW;
|
|
||||||
} else if (new_brightness >= 3) {
|
this->start_();
|
||||||
return TM1651_BRIGHTNESS_HIGH_HW;
|
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 tm1651
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_ARDUINO
|
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef USE_ARDUINO
|
#include "esphome/core/automation.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/automation.h"
|
|
||||||
|
|
||||||
#include <TM1651.h>
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace tm1651 {
|
namespace tm1651 {
|
||||||
|
|
||||||
enum TM1651Brightness : uint8_t {
|
enum TM1651Brightness : uint8_t {
|
||||||
TM1651_BRIGHTNESS_LOW = 1,
|
TM1651_DARKEST = 1,
|
||||||
TM1651_BRIGHTNESS_MEDIUM = 2,
|
TM1651_TYPICAL = 2,
|
||||||
TM1651_BRIGHTNESS_HIGH = 3,
|
TM1651_BRIGHTEST = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
class TM1651Display : public Component {
|
class TM1651Display : public Component {
|
||||||
@ -27,36 +21,49 @@ class TM1651Display : public Component {
|
|||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() 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(uint8_t new_brightness);
|
||||||
void set_brightness(TM1651Brightness new_brightness) { this->set_brightness(static_cast<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_off();
|
||||||
|
void turn_on();
|
||||||
|
|
||||||
protected:
|
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 *clk_pin_;
|
||||||
InternalGPIOPin *dio_pin_;
|
InternalGPIOPin *dio_pin_;
|
||||||
bool is_on_ = true;
|
|
||||||
|
|
||||||
uint8_t brightness_;
|
bool display_on_{true};
|
||||||
uint8_t level_;
|
uint8_t brightness_{};
|
||||||
|
uint8_t level_{0};
|
||||||
void repaint_();
|
|
||||||
|
|
||||||
uint8_t calculate_level_(uint8_t new_level);
|
|
||||||
uint8_t calculate_brightness_(uint8_t new_brightness);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class SetLevelPercentAction : public Action<Ts...>, public Parented<TM1651Display> {
|
template<typename... Ts> class SetBrightnessAction : public Action<Ts...>, public Parented<TM1651Display> {
|
||||||
public:
|
public:
|
||||||
TEMPLATABLE_VALUE(uint8_t, level_percent)
|
TEMPLATABLE_VALUE(uint8_t, brightness)
|
||||||
|
|
||||||
void play(Ts... x) override {
|
void play(Ts... x) override {
|
||||||
auto level_percent = this->level_percent_.value(x...);
|
auto brightness = this->brightness_.value(x...);
|
||||||
this->parent_->set_level_percent(level_percent);
|
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:
|
public:
|
||||||
TEMPLATABLE_VALUE(uint8_t, brightness)
|
TEMPLATABLE_VALUE(uint8_t, level_percent)
|
||||||
|
|
||||||
void play(Ts... x) override {
|
void play(Ts... x) override {
|
||||||
auto brightness = this->brightness_.value(x...);
|
auto level_percent = this->level_percent_.value(x...);
|
||||||
this->parent_->set_brightness(brightness);
|
this->parent_->set_level_percent(level_percent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -92,5 +99,3 @@ template<typename... Ts> class TurnOffAction : public Action<Ts...>, public Pare
|
|||||||
|
|
||||||
} // namespace tm1651
|
} // namespace tm1651
|
||||||
} // namespace esphome
|
} // 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
|
Loading…
x
Reference in New Issue
Block a user