Compare commits
10 commits
8b1417f8d7
...
9aa40ec69c
Author | SHA1 | Date | |
---|---|---|---|
|
9aa40ec69c | ||
|
5efc4d9922 | ||
|
2707331ca6 | ||
|
0e3af1bd47 | ||
|
6405af06fe | ||
|
8c3be33acb | ||
|
391f1c85d8 | ||
|
74f8c5830f | ||
|
72a8413e7b | ||
|
70ee692e20 |
21 changed files with 948 additions and 349 deletions
137
.clang-format
Normal file
137
.clang-format
Normal file
|
@ -0,0 +1,137 @@
|
|||
Language: Cpp
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 2000
|
||||
PointerAlignment: Right
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
160
.clang-tidy
Normal file
160
.clang-tidy
Normal file
|
@ -0,0 +1,160 @@
|
|||
---
|
||||
Checks: >-
|
||||
*,
|
||||
-abseil-*,
|
||||
-altera-*,
|
||||
-android-*,
|
||||
-boost-*,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-signed-char-misuse,
|
||||
-cert-dcl50-cpp,
|
||||
-cert-err58-cpp,
|
||||
-cert-oop57-cpp,
|
||||
-cert-str34-c,
|
||||
-clang-analyzer-optin.cplusplus.UninitializedObject,
|
||||
-clang-analyzer-osx.*,
|
||||
-clang-diagnostic-delete-abstract-non-virtual-dtor,
|
||||
-clang-diagnostic-delete-non-abstract-non-virtual-dtor,
|
||||
-clang-diagnostic-shadow-field,
|
||||
-clang-diagnostic-unused-const-variable,
|
||||
-clang-diagnostic-unused-parameter,
|
||||
-concurrency-*,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-cppcoreguidelines-init-variables,
|
||||
-cppcoreguidelines-macro-usage,
|
||||
-cppcoreguidelines-narrowing-conversions,
|
||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||
-cppcoreguidelines-pro-type-const-cast,
|
||||
-cppcoreguidelines-pro-type-cstyle-cast,
|
||||
-cppcoreguidelines-pro-type-member-init,
|
||||
-cppcoreguidelines-pro-type-reinterpret-cast,
|
||||
-cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
-cppcoreguidelines-pro-type-union-access,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
-cppcoreguidelines-special-member-functions,
|
||||
-fuchsia-multiple-inheritance,
|
||||
-fuchsia-overloaded-operator,
|
||||
-fuchsia-statically-constructed-objects,
|
||||
-fuchsia-default-arguments-declarations,
|
||||
-fuchsia-default-arguments-calls,
|
||||
-google-build-using-namespace,
|
||||
-google-explicit-constructor,
|
||||
-google-readability-braces-around-statements,
|
||||
-google-readability-casting,
|
||||
-google-readability-namespace-comments,
|
||||
-google-readability-todo,
|
||||
-google-runtime-references,
|
||||
-hicpp-*,
|
||||
-llvm-else-after-return,
|
||||
-llvm-header-guard,
|
||||
-llvm-include-order,
|
||||
-llvm-qualified-auto,
|
||||
-llvmlibc-*,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-no-recursion,
|
||||
-misc-unused-parameters,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-avoid-bind,
|
||||
-modernize-concat-nested-namespaces,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-use-auto,
|
||||
-modernize-use-default-member-init,
|
||||
-modernize-use-equals-default,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-use-nodiscard,
|
||||
-mpi-*,
|
||||
-objc-*,
|
||||
-readability-convert-member-functions-to-static,
|
||||
-readability-else-after-return,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-implicit-bool-conversion,
|
||||
-readability-isolate-declaration,
|
||||
-readability-magic-numbers,
|
||||
-readability-make-member-function-const,
|
||||
-readability-redundant-string-init,
|
||||
-readability-uppercase-literal-suffix,
|
||||
-readability-use-anyofallof,
|
||||
WarningsAsErrors: '*'
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: google
|
||||
CheckOptions:
|
||||
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||
value: '1'
|
||||
- key: google-readability-function-size.StatementThreshold
|
||||
value: '800'
|
||||
- key: google-runtime-int.TypeSuffix
|
||||
value: '_t'
|
||||
- key: llvm-namespace-comment.ShortNamespaceLines
|
||||
value: '10'
|
||||
- key: llvm-namespace-comment.SpacesBeforeComments
|
||||
value: '2'
|
||||
- key: modernize-loop-convert.MaxCopySize
|
||||
value: '16'
|
||||
- key: modernize-loop-convert.MinConfidence
|
||||
value: reasonable
|
||||
- key: modernize-loop-convert.NamingStyle
|
||||
value: CamelCase
|
||||
- key: modernize-pass-by-value.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-use-nullptr.NullMacros
|
||||
value: 'NULL'
|
||||
- key: modernize-make-unique.MakeSmartPtrFunction
|
||||
value: 'make_unique'
|
||||
- key: modernize-make-unique.MakeSmartPtrFunctionHeader
|
||||
value: 'esphome/core/helpers.h'
|
||||
- key: readability-braces-around-statements.ShortStatementLines
|
||||
value: 2
|
||||
- key: readability-identifier-naming.LocalVariableCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.ClassCase
|
||||
value: 'CamelCase'
|
||||
- key: readability-identifier-naming.StructCase
|
||||
value: 'CamelCase'
|
||||
- key: readability-identifier-naming.EnumCase
|
||||
value: 'CamelCase'
|
||||
- key: readability-identifier-naming.EnumConstantCase
|
||||
value: 'UPPER_CASE'
|
||||
- key: readability-identifier-naming.StaticConstantCase
|
||||
value: 'UPPER_CASE'
|
||||
- key: readability-identifier-naming.StaticVariableCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.GlobalConstantCase
|
||||
value: 'UPPER_CASE'
|
||||
- key: readability-identifier-naming.ParameterCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.PrivateMemberCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.PrivateMemberSuffix
|
||||
value: '_'
|
||||
- key: readability-identifier-naming.PrivateMethodCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.PrivateMethodSuffix
|
||||
value: '_'
|
||||
- key: readability-identifier-naming.ClassMemberCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.ClassMemberCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.ProtectedMemberCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.ProtectedMemberSuffix
|
||||
value: '_'
|
||||
- key: readability-identifier-naming.FunctionCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.ClassMethodCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.ProtectedMethodCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.ProtectedMethodSuffix
|
||||
value: '_'
|
||||
- key: readability-identifier-naming.VirtualMethodCase
|
||||
value: 'lower_case'
|
||||
- key: readability-identifier-naming.VirtualMethodSuffix
|
||||
value: ''
|
||||
- key: readability-qualified-auto.AddConstToQualified
|
||||
value: 0
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -8,3 +8,5 @@
|
|||
living_room_screen.yaml
|
||||
fonts
|
||||
__pycache__
|
||||
mlhx/
|
||||
v1/
|
||||
|
|
|
@ -2,9 +2,9 @@ esphome:
|
|||
name: ${device_id}
|
||||
name_add_mac_suffix: true
|
||||
on_boot:
|
||||
- priority: 750.0
|
||||
- priority: 220.0
|
||||
then:
|
||||
- IT8951E.clear
|
||||
- it8951e.clear
|
||||
- delay: 100ms
|
||||
- component.update: m5paper_display
|
||||
- priority: -100.0
|
||||
|
@ -13,13 +13,16 @@ esphome:
|
|||
- component.update: m5paper_display
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
board: m5stack-grey
|
||||
framework:
|
||||
type: arduino
|
||||
|
||||
external_components:
|
||||
- source: github://Passific/m5paper_esphome
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
level: VERBOSE
|
||||
level: DEBUG
|
||||
|
||||
# Enable psram
|
||||
psram:
|
||||
|
@ -83,7 +86,7 @@ globals:
|
|||
{"mdi-numeric-8-circle-outline", ""},
|
||||
{"mdi-numeric-9-plus-circle-outline", ""},
|
||||
}
|
||||
|
||||
|
||||
font:
|
||||
- file: 'gfonts://Roboto'
|
||||
id: normal_font
|
||||
|
@ -109,7 +112,7 @@ font:
|
|||
]
|
||||
- file: "fonts/materialdesignicons-webfont.ttf"
|
||||
id: weather_font
|
||||
size: 256
|
||||
size: 256
|
||||
glyphs: [
|
||||
'', #mdi-weather-night
|
||||
'', #mdi-weather-cloudy
|
||||
|
@ -137,7 +140,7 @@ font:
|
|||
'', #mdi-battery-medium
|
||||
'', #mdi-battery-low
|
||||
'', #mdi-battery-alert-variant-outline
|
||||
'', #mdi-battery-charging-high
|
||||
'', #mdi-battery-charging-high
|
||||
'', #mdi-battery-unknown
|
||||
]
|
||||
- file: "fonts/materialdesignicons-webfont.ttf"
|
||||
|
@ -162,7 +165,7 @@ font:
|
|||
'', #mdi-numeric-8-circle-outline
|
||||
'', #mdi-numeric-9-plus-circle-outline
|
||||
]
|
||||
|
||||
|
||||
spi:
|
||||
clk_pin: GPIO14
|
||||
mosi_pin: GPIO12
|
||||
|
@ -175,8 +178,9 @@ i2c:
|
|||
display:
|
||||
- platform: it8951e
|
||||
id: m5paper_display
|
||||
display_cs_pin: GPIO15
|
||||
cs_pin: GPIO15
|
||||
reset_pin: GPIO23
|
||||
reset_duration: 100ms
|
||||
busy_pin: GPIO27
|
||||
rotation: 0
|
||||
reversed: False
|
||||
|
@ -344,7 +348,7 @@ display:
|
|||
float battery_level = id(m5paper_battery_level).state;
|
||||
if (NOT_NAN(battery_level))
|
||||
{
|
||||
|
||||
|
||||
if (battery_level < 10)
|
||||
battery_icon = id(material_icons_map)["mdi-battery-alert-variant-outline"];
|
||||
else if (battery_level < 40)
|
||||
|
@ -492,8 +496,9 @@ switch:
|
|||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
id: ha_time
|
||||
on_time_sync:
|
||||
id: homeassistant_time
|
||||
timezone: Europe/Paris
|
||||
on_time_sync:
|
||||
- bm8563.write_time
|
||||
- platform: bm8563
|
||||
id: rtc_time
|
||||
|
@ -506,14 +511,17 @@ time:
|
|||
m5paper:
|
||||
battery_power_pin: GPIO5
|
||||
main_power_pin: GPIO2
|
||||
update_interval: 10s
|
||||
battery_voltage:
|
||||
name: ${device_name} battery voltage
|
||||
id: m5paper_battery_voltage
|
||||
device_class: "voltage"
|
||||
state_class: "measurement"
|
||||
|
||||
sensor:
|
||||
- platform: adc
|
||||
disabled_by_default: true
|
||||
pin: GPIO35
|
||||
name: ${device_name} battery voltage
|
||||
id: m5paper_battery_voltage
|
||||
update_interval: 10s
|
||||
attenuation: 11db
|
||||
filters:
|
||||
- multiply: 2 #1,27272727
|
||||
- platform: sht3xd
|
||||
temperature:
|
||||
name: ${device_name} temperature
|
||||
|
@ -539,20 +547,19 @@ sensor:
|
|||
update_interval: 20s
|
||||
lambda: |-
|
||||
constexpr float min_level = 3.52;
|
||||
constexpr float max_level = 4.1;
|
||||
float level = ((id(m5paper_battery_voltage).state - min_level) / (max_level - min_level)) * 100.00;
|
||||
if (level < 0)
|
||||
return 0;
|
||||
if (level > 100)
|
||||
return 100;
|
||||
return level;
|
||||
constexpr float max_level = 4.15;
|
||||
return ((id(m5paper_battery_voltage).state - min_level) / (max_level - min_level)) * 100.00;
|
||||
filters:
|
||||
- clamp:
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
- platform: homeassistant
|
||||
name: Outdoor temperature
|
||||
id: outdoor_temperature
|
||||
entity_id: ${outdoor_temperature}
|
||||
- platform: homeassistant
|
||||
name: Outdoor humidity
|
||||
id: outdoor_humidity
|
||||
id: outdoor_humidity
|
||||
entity_id: ${outdoor_humidity}
|
||||
- platform: homeassistant
|
||||
name: Rainfall last hour
|
||||
|
@ -563,7 +570,7 @@ sensor:
|
|||
id: outdoor_wind_strength
|
||||
entity_id: ${outdoor_wind_strength}
|
||||
- platform: homeassistant
|
||||
name: Indoor temprature
|
||||
name: Indoor temperature
|
||||
id: indoor_temperature
|
||||
entity_id: ${indoor_temperature}
|
||||
- platform: homeassistant
|
||||
|
@ -612,21 +619,21 @@ binary_sensor:
|
|||
name: ${device_name} right button
|
||||
id: right_button
|
||||
icon: mdi:gesture-tap-button
|
||||
pin:
|
||||
pin:
|
||||
number: GPIO37
|
||||
inverted: true
|
||||
on_release:
|
||||
on_release:
|
||||
- component.update: m5paper_display
|
||||
- platform: gpio
|
||||
name: ${device_name} BTN/PWR button
|
||||
icon: mdi:gesture-tap-button
|
||||
pin:
|
||||
pin:
|
||||
number: GPIO38
|
||||
inverted: true
|
||||
- platform: gpio
|
||||
name: ${device_name} left button
|
||||
icon: mdi:gesture-tap-button
|
||||
pin:
|
||||
pin:
|
||||
number: GPIO39
|
||||
inverted: true
|
||||
- platform: homeassistant
|
||||
|
|
11
NOTES.md
Normal file
11
NOTES.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Power
|
||||
|
||||
PS_ON / GPIO2 enables the battery
|
||||
|
||||
Wake up on:
|
||||
|
||||
- KEY_PUSH / GPIO38 - rocker pushed in
|
||||
- RTC_ALM
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
# m5paper_esphome
|
||||
|
||||
Based on https://github.com/sebirdman/m5paper_esphome
|
||||
Based on https://github.com/paveldn/m5paper_esphome
|
||||
|
||||
Himself based on https://github.com/sebirdman/m5paper_esphome
|
||||
|
||||
![Screen example](./img/screen_demo.jpg)
|
||||
|
||||
|
@ -8,7 +10,6 @@ Work in progress
|
|||
|
||||
All components are functional, but likely have bugs.
|
||||
|
||||
Please, download font from https://materialdesignicons.com/ and put in font folder
|
||||
Please, download font from https://materialdesignicons.com/ and put in 'fonts' folder
|
||||
|
||||
GT911 work based on: https://github.com/TomG736/esphome-GT911
|
||||
BM8563 work based on: https://github.com/TomG736/esphome-BM8563
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
@echo off
|
||||
if [%1] == [] goto err
|
||||
powershell -command "esphome compile %1 2>&1 | ? {$_.ToString().trim().Length -ne \"\" } | tee -filepath buildlog.txt"
|
||||
goto:eof
|
||||
:err
|
||||
echo Please use with esphome configuration as parameter
|
||||
echo Example: build.cmd haier.yaml
|
|
@ -1,7 +0,0 @@
|
|||
@echo off
|
||||
if [%1] == [] goto err
|
||||
wsl --cd "%cd%" /bin/sh -c "esphome compile %1 2>&1 | tee buildlog.txt"
|
||||
goto:eof
|
||||
:err
|
||||
echo Please use with esphome configuration as parameter
|
||||
echo Example: build.cmd haier.yaml
|
|
@ -1,28 +1,31 @@
|
|||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/i2c/i2c_bus.h"
|
||||
#include "bm8563.h"
|
||||
|
||||
#include "esphome/components/i2c/i2c_bus.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace bm8563 {
|
||||
|
||||
static const char *TAG = "bm8563.sensor";
|
||||
static const char* TAG = "bm8563.sensor";
|
||||
|
||||
void BM8563::setup(){
|
||||
this->write_byte_16(0,0);
|
||||
void BM8563::setup() {
|
||||
this->write_byte_16(0, 0);
|
||||
this->setupComplete = true;
|
||||
}
|
||||
|
||||
void BM8563::update(){
|
||||
if(!this->setupComplete){
|
||||
return;
|
||||
void BM8563::update() {
|
||||
if (!this->setupComplete) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "update");
|
||||
this->read_time();
|
||||
}
|
||||
|
||||
void BM8563::dump_config(){
|
||||
void BM8563::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "BM8563:");
|
||||
ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_);
|
||||
ESP_LOGCONFIG(TAG, " setupComplete: %s", this->setupComplete ? "true" : "false");
|
||||
ESP_LOGCONFIG(TAG, " setupComplete: %s",
|
||||
this->setupComplete ? "true" : "false");
|
||||
if (this->sleep_duration_.has_value()) {
|
||||
uint32_t duration = *this->sleep_duration_;
|
||||
ESP_LOGCONFIG(TAG, " Sleep Duration: %u ms", duration);
|
||||
|
@ -49,16 +52,16 @@ void BM8563::write_time() {
|
|||
}
|
||||
|
||||
BM8563_TimeTypeDef BM8563_TimeStruct = {
|
||||
hours: int8_t(now.hour),
|
||||
minutes: int8_t(now.minute),
|
||||
seconds: int8_t(now.second),
|
||||
hours : int8_t(now.hour),
|
||||
minutes : int8_t(now.minute),
|
||||
seconds : int8_t(now.second),
|
||||
};
|
||||
|
||||
BM8563_DateTypeDef BM8563_DateStruct = {
|
||||
day: int8_t(now.day_of_month),
|
||||
week: int8_t(now.day_of_week),
|
||||
month: int8_t(now.month),
|
||||
year: int16_t(now.year)
|
||||
day : int8_t(now.day_of_month),
|
||||
week : int8_t(now.day_of_week),
|
||||
month : int8_t(now.month),
|
||||
year : int16_t(now.year)
|
||||
};
|
||||
|
||||
this->setTime(&BM8563_TimeStruct);
|
||||
|
@ -66,37 +69,36 @@ void BM8563::write_time() {
|
|||
}
|
||||
|
||||
void BM8563::read_time() {
|
||||
ESP_LOGI(TAG, "Status2: %x %d", ReadReg(0x01), ReadReg(0x0F));
|
||||
|
||||
BM8563_TimeTypeDef BM8563_TimeStruct;
|
||||
BM8563_DateTypeDef BM8563_DateStruct;
|
||||
getTime(&BM8563_TimeStruct);
|
||||
getDate(&BM8563_DateStruct);
|
||||
ESP_LOGD(TAG, "BM8563: %i-%i-%i %i, %i:%i:%i",
|
||||
BM8563_DateStruct.year,
|
||||
BM8563_DateStruct.month,
|
||||
BM8563_DateStruct.day,
|
||||
BM8563_DateStruct.week,
|
||||
BM8563_TimeStruct.hours,
|
||||
BM8563_TimeStruct.minutes,
|
||||
BM8563_TimeStruct.seconds
|
||||
);
|
||||
ESP_LOGD(TAG, "BM8563: %i-%i-%i %i, %i:%i:%i", BM8563_DateStruct.year,
|
||||
BM8563_DateStruct.month, BM8563_DateStruct.day,
|
||||
BM8563_DateStruct.week, BM8563_TimeStruct.hours,
|
||||
BM8563_TimeStruct.minutes, BM8563_TimeStruct.seconds);
|
||||
|
||||
ESPTime rtc_time{.second = uint8_t(BM8563_TimeStruct.seconds),
|
||||
.minute = uint8_t(BM8563_TimeStruct.minutes),
|
||||
.hour = uint8_t(BM8563_TimeStruct.hours),
|
||||
.day_of_week = uint8_t(BM8563_DateStruct.week),
|
||||
.day_of_month = uint8_t(BM8563_DateStruct.day),
|
||||
.day_of_year = 1, // ignored by recalc_timestamp_utc(false)
|
||||
.month = uint8_t(BM8563_DateStruct.month),
|
||||
.year = uint16_t(BM8563_DateStruct.year)
|
||||
};
|
||||
ESPTime rtc_time{
|
||||
.second = uint8_t(BM8563_TimeStruct.seconds),
|
||||
.minute = uint8_t(BM8563_TimeStruct.minutes),
|
||||
.hour = uint8_t(BM8563_TimeStruct.hours),
|
||||
.day_of_week = uint8_t(BM8563_DateStruct.week),
|
||||
.day_of_month = uint8_t(BM8563_DateStruct.day),
|
||||
.day_of_year = 1, // ignored by recalc_timestamp_utc(false)
|
||||
.month = uint8_t(BM8563_DateStruct.month),
|
||||
.year = uint16_t(BM8563_DateStruct.year),
|
||||
.is_dst = false, // ignored by recalc_timestamp_utc()
|
||||
.timestamp = 0 // result
|
||||
};
|
||||
rtc_time.recalc_timestamp_utc(false);
|
||||
time::RealTimeClock::synchronize_epoch_(rtc_time.timestamp);
|
||||
}
|
||||
|
||||
bool BM8563::getVoltLow() {
|
||||
uint8_t data = ReadReg(0x02);
|
||||
return data & 0x80; // RTCC_VLSEC_MASK
|
||||
return data & 0x80; // RTCC_VLSEC_MASK
|
||||
}
|
||||
|
||||
uint8_t BM8563::bcd2ToByte(uint8_t value) {
|
||||
|
@ -123,18 +125,16 @@ void BM8563::getTime(BM8563_TimeTypeDef* BM8563_TimeStruct) {
|
|||
|
||||
BM8563_TimeStruct->seconds = bcd2ToByte(buf[0] & 0x7f);
|
||||
BM8563_TimeStruct->minutes = bcd2ToByte(buf[1] & 0x7f);
|
||||
BM8563_TimeStruct->hours = bcd2ToByte(buf[2] & 0x3f);
|
||||
BM8563_TimeStruct->hours = bcd2ToByte(buf[2] & 0x3f);
|
||||
}
|
||||
|
||||
void BM8563::setTime(BM8563_TimeTypeDef* BM8563_TimeStruct) {
|
||||
if (BM8563_TimeStruct == NULL) {
|
||||
return;
|
||||
}
|
||||
uint8_t buf[3] = {
|
||||
byteToBcd2(BM8563_TimeStruct->seconds),
|
||||
byteToBcd2(BM8563_TimeStruct->minutes),
|
||||
byteToBcd2(BM8563_TimeStruct->hours)
|
||||
};
|
||||
uint8_t buf[3] = {byteToBcd2(BM8563_TimeStruct->seconds),
|
||||
byteToBcd2(BM8563_TimeStruct->minutes),
|
||||
byteToBcd2(BM8563_TimeStruct->hours)};
|
||||
|
||||
this->write_register(0x02, buf, 3);
|
||||
}
|
||||
|
@ -143,9 +143,9 @@ void BM8563::getDate(BM8563_DateTypeDef* BM8563_DateStruct) {
|
|||
uint8_t buf[4] = {0};
|
||||
this->read_register(0x05, buf, 5);
|
||||
|
||||
BM8563_DateStruct->day = bcd2ToByte(buf[0] & 0x3f);
|
||||
BM8563_DateStruct->day = bcd2ToByte(buf[0] & 0x3f);
|
||||
BM8563_DateStruct->week = bcd2ToByte(buf[1] & 0x07);
|
||||
BM8563_DateStruct->month = bcd2ToByte(buf[2] & 0x1f);
|
||||
BM8563_DateStruct->month = bcd2ToByte(buf[2] & 0x1f);
|
||||
|
||||
uint8_t year_byte = bcd2ToByte(buf[3] & 0xff);
|
||||
ESP_LOGD(TAG, "Year byte is %i", year_byte);
|
||||
|
@ -161,20 +161,19 @@ void BM8563::setDate(BM8563_DateTypeDef* BM8563_DateStruct) {
|
|||
return;
|
||||
}
|
||||
uint8_t buf[4] = {
|
||||
byteToBcd2(BM8563_DateStruct->day),
|
||||
byteToBcd2(BM8563_DateStruct->week),
|
||||
byteToBcd2(BM8563_DateStruct->month),
|
||||
byteToBcd2((uint8_t)(BM8563_DateStruct->year % 100)),
|
||||
byteToBcd2(BM8563_DateStruct->day),
|
||||
byteToBcd2(BM8563_DateStruct->week),
|
||||
byteToBcd2(BM8563_DateStruct->month),
|
||||
byteToBcd2((uint8_t)(BM8563_DateStruct->year % 100)),
|
||||
};
|
||||
|
||||
|
||||
if (BM8563_DateStruct->year < 2000) {
|
||||
buf[2] = byteToBcd2(BM8563_DateStruct->month) | 0x80;
|
||||
} else {
|
||||
buf[2] = byteToBcd2(BM8563_DateStruct->month) | 0x00;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "WRiting year is %i", buf[3]);
|
||||
ESP_LOGI(TAG, "Writing year is %i", buf[3]);
|
||||
this->write_register(0x05, buf, 4);
|
||||
}
|
||||
|
||||
|
@ -188,7 +187,7 @@ uint8_t BM8563::ReadReg(uint8_t reg) {
|
|||
return data;
|
||||
}
|
||||
|
||||
int BM8563::SetAlarmIRQ(int afterSeconds) {
|
||||
void BM8563::SetAlarmIRQ(int afterSeconds) {
|
||||
ESP_LOGI(TAG, "Sleep Duration: %u ms", afterSeconds);
|
||||
uint8_t reg_value = 0;
|
||||
reg_value = ReadReg(0x01);
|
||||
|
@ -198,26 +197,28 @@ int BM8563::SetAlarmIRQ(int afterSeconds) {
|
|||
WriteReg(0x01, reg_value);
|
||||
reg_value = 0x03;
|
||||
WriteReg(0x0E, reg_value);
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t type_value = 2;
|
||||
uint8_t div = 1;
|
||||
if (afterSeconds > 255) {
|
||||
div = 60;
|
||||
type_value = 0x83;
|
||||
uint8_t td;
|
||||
if (afterSeconds <= (255 * 1000 / 64)) {
|
||||
td = 0x81;
|
||||
afterSeconds = afterSeconds * 64 / 1000;
|
||||
} else if (afterSeconds / 1000 <= 255) {
|
||||
td = 0x82;
|
||||
afterSeconds /= 1000;
|
||||
} else {
|
||||
type_value = 0x82;
|
||||
td = 0x83;
|
||||
afterSeconds /= 60000;
|
||||
}
|
||||
|
||||
afterSeconds = (afterSeconds / div) & 0xFF;
|
||||
WriteReg(0x0F, afterSeconds);
|
||||
WriteReg(0x0E, type_value);
|
||||
WriteReg(0x0E, td);
|
||||
WriteReg(0x0F, std::min(afterSeconds, 0xFF));
|
||||
ESP_LOGI(TAG, "%d %x", afterSeconds, td);
|
||||
|
||||
reg_value |= (1 << 0);
|
||||
reg_value &= ~(1 << 7);
|
||||
WriteReg(0x01, reg_value);
|
||||
return afterSeconds * div;
|
||||
}
|
||||
|
||||
void BM8563::clearIRQ() {
|
||||
|
@ -232,4 +233,4 @@ void BM8563::disableIRQ() {
|
|||
}
|
||||
|
||||
} // namespace bm8563
|
||||
} // namespace esphome
|
||||
} // namespace esphome
|
||||
|
|
|
@ -27,7 +27,7 @@ class BM8563 : public time::RealTimeClock, public i2c::I2CDevice {
|
|||
void setup() override;
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
|
||||
|
||||
void set_sleep_duration(uint32_t time_ms);
|
||||
void write_time();
|
||||
void read_time();
|
||||
|
@ -42,7 +42,7 @@ class BM8563 : public time::RealTimeClock, public i2c::I2CDevice {
|
|||
void setTime(BM8563_TimeTypeDef* BM8563_TimeStruct);
|
||||
void setDate(BM8563_DateTypeDef* BM8563_DateStruct);
|
||||
|
||||
int SetAlarmIRQ(int afterSeconds);
|
||||
void SetAlarmIRQ(int afterSeconds);
|
||||
int SetAlarmIRQ(const BM8563_TimeTypeDef &BM8563_TimeStruct);
|
||||
int SetAlarmIRQ(const BM8563_DateTypeDef &BM8563_DateStruct, const BM8563_TimeTypeDef &BM8563_TimeStruct);
|
||||
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
```yaml
|
||||
# example configuration:
|
||||
|
||||
sensor:
|
||||
- platform: empty_spi_sensor
|
||||
name: Empty SPI sensor
|
||||
cs_pin: D8
|
||||
|
||||
spi:
|
||||
clk_pin: D5
|
||||
miso_pin: D6
|
||||
clk_pin: GPIO14
|
||||
mosi_pin: GPIO12
|
||||
miso_pin: GPIO13
|
||||
|
||||
display:
|
||||
- platform: it8951e
|
||||
id: m5paper_display
|
||||
cs_pin: GPIO15
|
||||
reset_pin: GPIO23
|
||||
reset_duration: 100ms
|
||||
busy_pin: GPIO27
|
||||
rotation: 0
|
||||
reversed: False
|
||||
update_interval: never
|
||||
```
|
|
@ -12,6 +12,7 @@ from esphome.const import (
|
|||
CONF_BUSY_PIN,
|
||||
CONF_PAGES,
|
||||
CONF_LAMBDA,
|
||||
CONF_MODEL,
|
||||
CONF_REVERSED,
|
||||
)
|
||||
|
||||
|
@ -23,6 +24,12 @@ IT8951ESensor = it8951e_ns.class_(
|
|||
)
|
||||
ClearAction = it8951e_ns.class_("ClearAction", automation.Action)
|
||||
|
||||
it8951eModel = it8951e_ns.enum("it8951eModel")
|
||||
|
||||
MODELS = {
|
||||
"M5EPD": it8951eModel.M5EPD
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
display.FULL_DISPLAY_SCHEMA.extend(
|
||||
{
|
||||
|
@ -35,6 +42,9 @@ CONFIG_SCHEMA = cv.All(
|
|||
cv.positive_time_period_milliseconds,
|
||||
cv.Range(max=core.TimePeriod(milliseconds=500)),
|
||||
),
|
||||
cv.Optional(CONF_MODEL, default="M5EPD"): cv.enum(
|
||||
MODELS, upper=True, space="_"
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("1s"))
|
||||
|
@ -43,7 +53,7 @@ CONFIG_SCHEMA = cv.All(
|
|||
)
|
||||
|
||||
@automation.register_action(
|
||||
"IT8951E.clear",
|
||||
"it8951e.clear",
|
||||
ClearAction,
|
||||
automation.maybe_simple_id(
|
||||
{
|
||||
|
@ -51,7 +61,7 @@ CONFIG_SCHEMA = cv.All(
|
|||
}
|
||||
),
|
||||
)
|
||||
async def bm8563_read_time_to_code(config, action_id, template_arg, args):
|
||||
async def it8951e_clear_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
|
||||
|
@ -63,6 +73,8 @@ async def to_code(config):
|
|||
await display.register_display(var, config)
|
||||
await spi.register_spi_device(var, config)
|
||||
|
||||
if CONF_MODEL in config:
|
||||
cg.add(var.set_model(config[CONF_MODEL]))
|
||||
if CONF_LAMBDA in config:
|
||||
lambda_ = await cg.process_lambda(
|
||||
config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void
|
||||
|
|
|
@ -30,17 +30,6 @@ IT8951 Command defines
|
|||
/*-----------------------------------------------------------------------
|
||||
IT8951 Mode defines
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
// Rotate mode
|
||||
#define IT8951_ROTATE_0 0
|
||||
#define IT8951_ROTATE_90 1
|
||||
#define IT8951_ROTATE_180 2
|
||||
#define IT8951_ROTATE_270 3
|
||||
|
||||
// Direction mode
|
||||
#define IT8951_DIRECTION_PORTRAIT 1
|
||||
#define IT8951_DIRECTION_LANDSCAPE 0
|
||||
|
||||
//Pixel mode (Bit per Pixel)
|
||||
#define IT8951_2BPP 0
|
||||
#define IT8951_3BPP 1
|
||||
|
|
|
@ -7,12 +7,6 @@
|
|||
namespace esphome {
|
||||
namespace it8951e {
|
||||
|
||||
//TODO: create model M5EPD
|
||||
#define M5EPD_PANEL_W 960
|
||||
#define M5EPD_PANEL_H 540
|
||||
#define M5EPD_PANEL_ADDRL 0x36E0
|
||||
#define M5EPD_PANEL_ADDRH 0x0012
|
||||
|
||||
static const char *TAG = "it8951e.display";
|
||||
|
||||
void IT8951ESensor::write_two_byte16(uint16_t type, uint16_t cmd) {
|
||||
|
@ -21,7 +15,7 @@ void IT8951ESensor::write_two_byte16(uint16_t type, uint16_t cmd) {
|
|||
|
||||
this->write_byte16(type);
|
||||
this->wait_busy();
|
||||
this->write_byte16(cmd);
|
||||
this->write_byte16(cmd);
|
||||
|
||||
this->disable();
|
||||
}
|
||||
|
@ -94,12 +88,9 @@ void IT8951ESensor::write_reg(uint16_t addr, uint16_t data) {
|
|||
this->disable();
|
||||
}
|
||||
|
||||
void IT8951ESensor::set_target_memory_addr(uint32_t tar_addr) {
|
||||
uint16_t h = (uint16_t)((tar_addr >> 16) & 0x0000FFFF);
|
||||
uint16_t l = (uint16_t)(tar_addr & 0x0000FFFF);
|
||||
|
||||
this->write_reg(IT8951_LISAR + 2, h);
|
||||
this->write_reg(IT8951_LISAR, l);
|
||||
void IT8951ESensor::set_target_memory_addr(uint16_t tar_addrL, uint16_t tar_addrH) {
|
||||
this->write_reg(IT8951_LISAR + 2, tar_addrH);
|
||||
this->write_reg(IT8951_LISAR, tar_addrL);
|
||||
}
|
||||
|
||||
void IT8951ESensor::write_args(uint16_t cmd, uint16_t *args, uint16_t length) {
|
||||
|
@ -109,34 +100,11 @@ void IT8951ESensor::write_args(uint16_t cmd, uint16_t *args, uint16_t length) {
|
|||
}
|
||||
}
|
||||
|
||||
void IT8951ESensor::set_rotation(uint16_t rotate) {
|
||||
if (rotate < 4) {
|
||||
this->m_rotate = rotate;
|
||||
} else if (rotate < 90) {
|
||||
this->m_rotate = IT8951_ROTATE_0;
|
||||
} else if (rotate < 180) {
|
||||
this->m_rotate = IT8951_ROTATE_90;
|
||||
} else if (rotate < 270) {
|
||||
this->m_rotate = IT8951_ROTATE_180;
|
||||
} else {
|
||||
this->m_rotate = IT8951_ROTATE_270;
|
||||
}
|
||||
|
||||
if (this->m_rotate == IT8951_ROTATE_0 || this->m_rotate == IT8951_ROTATE_180) {
|
||||
this->m_direction = IT8951_DIRECTION_PORTRAIT;
|
||||
this->device_info_.usPanelW = M5EPD_PANEL_W;
|
||||
this->device_info_.usPanelH = M5EPD_PANEL_H;
|
||||
} else {
|
||||
this->m_direction = IT8951_DIRECTION_LANDSCAPE;
|
||||
this->device_info_.usPanelW = M5EPD_PANEL_H;
|
||||
this->device_info_.usPanelH = M5EPD_PANEL_W;
|
||||
}
|
||||
}
|
||||
|
||||
void IT8951ESensor::set_area(uint16_t x, uint16_t y, uint16_t w,
|
||||
uint16_t h) {
|
||||
uint16_t args[5];
|
||||
args[0] = (this->m_endian_type << 8 | this->m_pix_bpp << 4 | this->m_rotate);
|
||||
|
||||
args[0] = (this->m_endian_type << 8 | this->m_pix_bpp << 4);
|
||||
args[1] = x;
|
||||
args[2] = y;
|
||||
args[3] = w;
|
||||
|
@ -177,8 +145,8 @@ void IT8951ESensor::check_busy(uint32_t timeout) {
|
|||
}
|
||||
|
||||
void IT8951ESensor::update_area(uint16_t x, uint16_t y, uint16_t w,
|
||||
uint16_t h, m5epd_update_mode_t mode) {
|
||||
if (mode == UPDATE_MODE_NONE) {
|
||||
uint16_t h, update_mode_e mode) {
|
||||
if (mode == update_mode_e::UPDATE_MODE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -195,35 +163,14 @@ void IT8951ESensor::update_area(uint16_t x, uint16_t y, uint16_t w,
|
|||
h = this->get_height_internal() - y;
|
||||
}
|
||||
|
||||
uint16_t tmp_x = x;
|
||||
uint16_t tmp_y = y;
|
||||
switch (this->m_rotate) {
|
||||
case IT8951_ROTATE_0:
|
||||
tmp_x = x;
|
||||
tmp_y = y;
|
||||
break;
|
||||
case IT8951_ROTATE_90:
|
||||
tmp_x = y;
|
||||
tmp_y = M5EPD_PANEL_H - w - x;
|
||||
break;
|
||||
case IT8951_ROTATE_180:
|
||||
tmp_x = M5EPD_PANEL_W - w - x;
|
||||
tmp_y = M5EPD_PANEL_H - h - y;
|
||||
break;
|
||||
case IT8951_ROTATE_270:
|
||||
tmp_x = M5EPD_PANEL_W - h - y;
|
||||
tmp_y = x;
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t args[7];
|
||||
args[0] = tmp_x;
|
||||
args[1] = tmp_y;
|
||||
args[0] = x;
|
||||
args[1] = y;
|
||||
args[2] = w;
|
||||
args[3] = h;
|
||||
args[4] = mode;
|
||||
args[5] = this->device_info_.usImgBufAddrL;
|
||||
args[6] = this->device_info_.usImgBufAddrH;
|
||||
args[5] = this->IT8951DevAll[this->model_].devInfo.usImgBufAddrL;
|
||||
args[6] = this->IT8951DevAll[this->model_].devInfo.usImgBufAddrH;
|
||||
|
||||
this->write_args(IT8951_I80_CMD_DPY_BUF_AREA, args, 7);
|
||||
}
|
||||
|
@ -238,9 +185,9 @@ void IT8951ESensor::reset(void) {
|
|||
|
||||
uint32_t IT8951ESensor::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal(); }
|
||||
|
||||
void IT8951ESensor::get_device_info(IT8951DevInfo *info) {
|
||||
void IT8951ESensor::get_device_info(struct IT8951DevInfo_s *info) {
|
||||
this->write_command(IT8951_I80_CMD_GET_DEV_INFO);
|
||||
this->read_words(info, sizeof(IT8951DevInfo)/2);//Polling HRDY for each words(2-bytes) if possible
|
||||
this->read_words(info, sizeof(struct IT8951DevInfo_s)/2); // Polling HRDY for each words(2-bytes) if possible
|
||||
}
|
||||
|
||||
uint16_t IT8951ESensor::get_vcom() {
|
||||
|
@ -268,17 +215,8 @@ void IT8951ESensor::setup() {
|
|||
|
||||
this->busy_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||
|
||||
this->get_device_info(&(this->device_info_));
|
||||
// this->get_device_info(&(this->device_info_));
|
||||
this->dump_config();
|
||||
if (!this->device_info_.usImgBufAddrH || !this->device_info_.usImgBufAddrL) {
|
||||
// Sometime it fails to read the device info
|
||||
ESP_LOGE(TAG, "FAILED to read panel image buffer address, try hard...");
|
||||
this->device_info_.usPanelW = M5EPD_PANEL_W;
|
||||
this->device_info_.usPanelH = M5EPD_PANEL_H;
|
||||
this->device_info_.usImgBufAddrL = M5EPD_PANEL_ADDRL;
|
||||
this->device_info_.usImgBufAddrH = M5EPD_PANEL_ADDRH;
|
||||
}
|
||||
this->set_rotation(IT8951_ROTATE_0);
|
||||
|
||||
this->write_command(IT8951_TCON_SYS_RUN);
|
||||
|
||||
|
@ -309,19 +247,18 @@ void IT8951ESensor::setup() {
|
|||
* @param y Update Y coordinate
|
||||
* @param w width of gram, >>> Must be a multiple of 4 <<<
|
||||
* @param h height of gram
|
||||
* @param gram 4bpp garm data
|
||||
* @retval m5epd_err_t
|
||||
* @param gram 4bpp gram data
|
||||
*/
|
||||
void IT8951ESensor::write_buffer_to_display(uint16_t x, uint16_t y, uint16_t w,
|
||||
uint16_t h, const uint8_t *gram) {
|
||||
this->m_endian_type = IT8951_LDIMG_B_ENDIAN;
|
||||
this->m_pix_bpp = IT8951_4BPP;
|
||||
if (x > this->get_width_internal() || y > this->get_height_internal()) {
|
||||
if (x > this->get_width() || y > this->get_height()) {
|
||||
ESP_LOGE(TAG, "Pos (%d, %d) out of bounds.", x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
this->set_target_memory_addr(this->device_info_.usImgBufAddrL | (this->device_info_.usImgBufAddrH << 16));
|
||||
this->set_target_memory_addr(this->IT8951DevAll[this->model_].devInfo.usImgBufAddrL, this->IT8951DevAll[this->model_].devInfo.usImgBufAddrH);
|
||||
this->set_area(x, y, w, h);
|
||||
|
||||
uint32_t pos = 0;
|
||||
|
@ -344,27 +281,24 @@ void IT8951ESensor::write_buffer_to_display(uint16_t x, uint16_t y, uint16_t w,
|
|||
}
|
||||
|
||||
void IT8951ESensor::write_display() {
|
||||
//this->write_command(IT8951_TCON_SYS_RUN);
|
||||
this->write_command(IT8951_TCON_SYS_RUN);
|
||||
this->write_buffer_to_display(0, 0, this->max_x, this->max_y, this->buffer_);
|
||||
this->update_area(0, 0, this->max_x, this->max_y, UPDATE_MODE_GC16);
|
||||
//this->update_area(0, 0, this->max_x, this->max_y, UPDATE_MODE_DU4);
|
||||
this->update_area(0, 0, this->max_x, this->max_y, update_mode_e::UPDATE_MODE_GC16);
|
||||
this->max_x = 0;
|
||||
this->max_y = 0;
|
||||
//this->write_command(IT8951_TCON_SLEEP);
|
||||
this->write_command(IT8951_TCON_SLEEP);
|
||||
}
|
||||
|
||||
|
||||
/** @brief Clear graphics buffer
|
||||
* @param init Screen initialization, If is 0, clear the buffer without
|
||||
* initializing
|
||||
* @retval m5epd_err_t
|
||||
* @param init Screen initialization, If is 0, clear the buffer without initializing
|
||||
*/
|
||||
void IT8951ESensor::clear(bool init) {
|
||||
this->m_endian_type = IT8951_LDIMG_L_ENDIAN;
|
||||
this->m_pix_bpp = IT8951_4BPP;
|
||||
|
||||
this->set_target_memory_addr(this->device_info_.usImgBufAddrL | (this->device_info_.usImgBufAddrH << 16));
|
||||
this->set_area(0, 0, this->get_width_internal(), this->get_height_internal());
|
||||
this->set_target_memory_addr(this->IT8951DevAll[this->model_].devInfo.usImgBufAddrL, this->IT8951DevAll[this->model_].devInfo.usImgBufAddrH);
|
||||
this->set_area(0, 0, this->get_width_internal(), this->get_height_internal());
|
||||
uint32_t looping = (this->get_width_internal() * this->get_height_internal()) >> 2;
|
||||
|
||||
for (uint32_t x = 0; x < looping; x++) {
|
||||
|
@ -377,18 +311,20 @@ void IT8951ESensor::clear(bool init) {
|
|||
this->write_command(IT8951_TCON_LD_IMG_END);
|
||||
|
||||
if (init) {
|
||||
this->update_area(0, 0, this->get_width_internal(), this->get_height_internal(), UPDATE_MODE_INIT);
|
||||
this->update_area(0, 0, this->get_width_internal(), this->get_height_internal(), update_mode_e::UPDATE_MODE_INIT);
|
||||
}
|
||||
}
|
||||
|
||||
void IT8951ESensor::update() {
|
||||
this->do_update_();
|
||||
this->write_display();
|
||||
if (this->is_ready()) {
|
||||
this->do_update_();
|
||||
this->write_display();
|
||||
}
|
||||
}
|
||||
|
||||
void HOT IT8951ESensor::draw_absolute_pixel_internal(int x, int y, Color color) {
|
||||
if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0) {
|
||||
// Removed to avoid too much logging
|
||||
// Removed to avoid too much logging
|
||||
// ESP_LOGE(TAG, "Drawing outside the screen size!");
|
||||
return;
|
||||
}
|
||||
|
@ -419,20 +355,27 @@ void HOT IT8951ESensor::draw_absolute_pixel_internal(int x, int y, Color color)
|
|||
}
|
||||
|
||||
int IT8951ESensor::get_width_internal() {
|
||||
return this->device_info_.usPanelW;
|
||||
return this->IT8951DevAll[this->model_].devInfo.usPanelW;
|
||||
}
|
||||
|
||||
int IT8951ESensor::get_height_internal() {
|
||||
return this->device_info_.usPanelH;
|
||||
return this->IT8951DevAll[this->model_].devInfo.usPanelH;
|
||||
}
|
||||
|
||||
void IT8951ESensor::dump_config() {
|
||||
ESP_LOGI(TAG, "Height:%d Width:%d LUT: %s, FW: %s, Mem:%x",
|
||||
this->device_info_.usPanelH,
|
||||
this->device_info_.usPanelW,
|
||||
this->device_info_.usLUTVersion,
|
||||
this->device_info_.usFWVersion,
|
||||
this->device_info_.usImgBufAddrL | (this->device_info_.usImgBufAddrH << 16)
|
||||
LOG_DISPLAY("", "IT8951E", this);
|
||||
switch (this->model_) {
|
||||
case it8951eModel::M5EPD:
|
||||
ESP_LOGCONFIG(TAG, " Model: M5EPD");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGCONFIG(TAG, " Model: unkown");
|
||||
break;
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, "LUT: %s, FW: %s, Mem:%x",
|
||||
this->IT8951DevAll[this->model_].devInfo.usLUTVersion,
|
||||
this->IT8951DevAll[this->model_].devInfo.usFWVersion,
|
||||
this->IT8951DevAll[this->model_].devInfo.usImgBufAddrL | (this->IT8951DevAll[this->model_].devInfo.usImgBufAddrH << 16)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,12 @@
|
|||
namespace esphome {
|
||||
namespace it8951e {
|
||||
|
||||
enum it8951eModel
|
||||
{
|
||||
M5EPD = 0,
|
||||
it8951eModelsEND // MUST be last
|
||||
};
|
||||
|
||||
#if ESPHOME_VERSION_CODE >= VERSION_CODE(2023, 12, 0)
|
||||
class IT8951ESensor : public display::DisplayBuffer,
|
||||
#else
|
||||
|
@ -18,7 +24,7 @@ class IT8951ESensor : public PollingComponent, public display::DisplayBuffer,
|
|||
spi::DATA_RATE_10MHZ> {
|
||||
public:
|
||||
float get_loop_priority() const override { return 0.0f; };
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; };
|
||||
float get_setup_priority() const override { return setup_priority::PROCESSOR; };
|
||||
|
||||
/*
|
||||
---------------------------------------- Refresh mode description
|
||||
|
@ -90,49 +96,47 @@ shown in Figure 1. The use of a white image in the transition from 4-bit to
|
|||
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t usPanelW; // these are incorrect
|
||||
uint16_t usPanelH; // on m5paper
|
||||
uint16_t usImgBufAddrL;
|
||||
uint16_t usImgBufAddrH;
|
||||
char usFWVersion[16]; // empty on m5paper
|
||||
char usLUTVersion[16]; // empty on m5paper
|
||||
}IT8951DevInfo;
|
||||
struct IT8951DevInfo_s
|
||||
{
|
||||
uint16_t usPanelW;
|
||||
uint16_t usPanelH;
|
||||
uint16_t usImgBufAddrL;
|
||||
uint16_t usImgBufAddrH;
|
||||
char usFWVersion[16];
|
||||
char usLUTVersion[16];
|
||||
};
|
||||
|
||||
typedef enum // Typical
|
||||
{ // Ghosting Update Time Usage
|
||||
UPDATE_MODE_INIT = 0, // * N/A 2000ms Display initialization,
|
||||
UPDATE_MODE_DU = 1, // Low 260ms Monochrome menu, text
|
||||
// input, and touch screen input
|
||||
UPDATE_MODE_GC16 = 2, // * Very Low 450ms High quality images
|
||||
UPDATE_MODE_GL16 =
|
||||
3, // * Medium 450ms Text with white background
|
||||
UPDATE_MODE_GLR16 =
|
||||
4, // Low 450ms Text with white background
|
||||
UPDATE_MODE_GLD16 =
|
||||
5, // Low 450ms Text and graphics with white background
|
||||
UPDATE_MODE_DU4 =
|
||||
6, // * Medium 120ms Fast page flipping at reduced contrast
|
||||
UPDATE_MODE_A2 = 7, // Medium 290ms Anti-aliased text in menus
|
||||
// / touch and screen input
|
||||
UPDATE_MODE_NONE = 8
|
||||
} m5epd_update_mode_t; // The ones marked with * are more commonly used
|
||||
struct IT8951Dev_s
|
||||
{
|
||||
struct IT8951DevInfo_s devInfo;
|
||||
display::DisplayType displayType;
|
||||
};
|
||||
|
||||
enum update_mode_e // Typical
|
||||
{ // Ghosting Update Time Usage
|
||||
UPDATE_MODE_INIT = 0, // * N/A 2000ms Display initialization,
|
||||
UPDATE_MODE_DU = 1, // Low 260ms Monochrome menu, text input, and touch screen input
|
||||
UPDATE_MODE_GC16 = 2, // * Very Low 450ms High quality images
|
||||
UPDATE_MODE_GL16 = 3, // * Medium 450ms Text with white background
|
||||
UPDATE_MODE_GLR16 = 4, // Low 450ms Text with white background
|
||||
UPDATE_MODE_GLD16 = 5, // Low 450ms Text and graphics with white background
|
||||
UPDATE_MODE_DU4 = 6, // * Medium 120ms Fast page flipping at reduced contrast
|
||||
UPDATE_MODE_A2 = 7, // Medium 290ms Anti-aliased text in menus / touch and screen input
|
||||
UPDATE_MODE_NONE = 8
|
||||
}; // The ones marked with * are more commonly used
|
||||
|
||||
void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; }
|
||||
void set_busy_pin(GPIOPin *busy) { this->busy_pin_ = busy; }
|
||||
|
||||
void set_rotation(uint16_t rotate);
|
||||
void set_reversed(bool reversed) { this->reversed_ = reversed; }
|
||||
void set_reset_duration(uint32_t reset_duration) { this->reset_duration_ = reset_duration; }
|
||||
|
||||
uint8_t get_rotate(void) { return m_rotate; };
|
||||
uint8_t get_direction(void) { return m_direction; };
|
||||
void set_model(it8951eModel model) { this->model_ = model; }
|
||||
|
||||
void setup() override;
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_BINARY; }
|
||||
|
||||
display::DisplayType get_display_type() override { return IT8951DevAll[this->model_].displayType; }
|
||||
|
||||
void clear(bool init);
|
||||
|
||||
|
@ -147,14 +151,22 @@ typedef enum // Typical
|
|||
|
||||
|
||||
private:
|
||||
IT8951DevInfo device_info_;
|
||||
struct IT8951Dev_s IT8951DevAll[it8951eModel::it8951eModelsEND]
|
||||
{ // it8951eModel::M5EPD
|
||||
960, // .devInfo.usPanelW
|
||||
540, // .devInfo.usPanelH
|
||||
0x36E0, // .devInfo.usImgBufAddrL
|
||||
0x0012, // .devInfo.usImgBufAddrH
|
||||
"", // .devInfo.usFWVersion
|
||||
"", // .devInfo.usFWVersion
|
||||
display::DisplayType::DISPLAY_TYPE_GRAYSCALE // .displayType (M5EPD supports 16 gray scale levels)
|
||||
};
|
||||
|
||||
uint8_t *should_write_buffer_{nullptr};
|
||||
void get_device_info(IT8951DevInfo *info);
|
||||
void get_device_info(struct IT8951DevInfo_s *info);
|
||||
|
||||
uint32_t max_x = 0;
|
||||
uint32_t max_y = 0;
|
||||
uint8_t m_rotate = 0;
|
||||
uint8_t m_direction = 1;
|
||||
uint16_t m_endian_type, m_pix_bpp;
|
||||
|
||||
|
||||
|
@ -163,6 +175,7 @@ typedef enum // Typical
|
|||
|
||||
bool reversed_ = false;
|
||||
uint32_t reset_duration_{100};
|
||||
enum it8951eModel model_{it8951eModel::M5EPD};
|
||||
|
||||
void reset(void);
|
||||
|
||||
|
@ -180,12 +193,12 @@ typedef enum // Typical
|
|||
void write_command(uint16_t cmd);
|
||||
void write_word(uint16_t cmd);
|
||||
void write_reg(uint16_t addr, uint16_t data);
|
||||
void set_target_memory_addr(uint32_t tar_addr);
|
||||
void set_target_memory_addr(uint16_t tar_addrL, uint16_t tar_addrH);
|
||||
void write_args(uint16_t cmd, uint16_t *args, uint16_t length);
|
||||
|
||||
void set_area(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
void update_area(uint16_t x, uint16_t y, uint16_t w,
|
||||
uint16_t h, m5epd_update_mode_t mode);
|
||||
uint16_t h, update_mode_e mode);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2,18 +2,13 @@ import esphome.codegen as cg
|
|||
from esphome import pins
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.components import sensor
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
CONF_BATTERY_VOLTAGE,
|
||||
UNIT_VOLT,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
CONF_ID,
|
||||
)
|
||||
|
||||
m5paper_ns = cg.esphome_ns.namespace('m5paper')
|
||||
|
||||
M5PaperComponent = m5paper_ns.class_('M5PaperComponent', cg.PollingComponent)
|
||||
M5PaperComponent = m5paper_ns.class_('M5PaperComponent', cg.Component)
|
||||
PowerAction = m5paper_ns.class_("PowerAction", automation.Action)
|
||||
|
||||
CONF_MAIN_POWER_PIN = "main_power_pin"
|
||||
|
@ -22,14 +17,8 @@ CONF_BATTERY_POWER_PIN = "battery_power_pin"
|
|||
CONFIG_SCHEMA = cv.Schema({
|
||||
cv.GenerateID(): cv.declare_id(M5PaperComponent),
|
||||
cv.Required(CONF_MAIN_POWER_PIN): pins.gpio_output_pin_schema,
|
||||
cv.Required(CONF_BATTERY_POWER_PIN): pins.gpio_output_pin_schema,
|
||||
cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_VOLT,
|
||||
accuracy_decimals=3,
|
||||
device_class=DEVICE_CLASS_VOLTAGE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
}).extend(cv.polling_component_schema('60s'))
|
||||
cv.Required(CONF_BATTERY_POWER_PIN): pins.gpio_output_pin_schema
|
||||
})
|
||||
|
||||
@automation.register_action(
|
||||
"m5paper.shutdown_main_power",
|
||||
|
@ -55,7 +44,4 @@ async def to_code(config):
|
|||
cg.add(var.set_main_power_pin(power))
|
||||
if CONF_BATTERY_POWER_PIN in config:
|
||||
power = await cg.gpio_pin_expression(config[CONF_BATTERY_POWER_PIN])
|
||||
cg.add(var.set_battery_power_pin(power))
|
||||
if CONF_BATTERY_VOLTAGE in config:
|
||||
sens = await sensor.new_sensor(config[CONF_BATTERY_VOLTAGE])
|
||||
cg.add(var.set_battery_voltage(sens))
|
||||
cg.add(var.set_battery_power_pin(power))
|
|
@ -1,14 +1,10 @@
|
|||
#include "esphome/core/log.h"
|
||||
#include "m5paper.h"
|
||||
#include "soc/adc_channel.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace m5paper {
|
||||
|
||||
#define BASE_VOLATAGE 3600
|
||||
#define SCALE 0.5//0.78571429
|
||||
#define ADC_FILTER_SAMPLE 16
|
||||
|
||||
// hack to hold power lines up in deep sleep mode
|
||||
// battery life isn't great with deep sleep, recommend bm8563 sleep
|
||||
#define ALLOW_ESPHOME_DEEP_SLEEP true
|
||||
|
@ -16,7 +12,7 @@ namespace m5paper {
|
|||
static const char *TAG = "m5paper.component";
|
||||
|
||||
void M5PaperComponent::setup() {
|
||||
ESP_LOGE(TAG, "m5paper starting up!");
|
||||
ESP_LOGCONFIG(TAG, "m5paper starting up!");
|
||||
this->main_power_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||
this->main_power_pin_->digital_write(true);
|
||||
|
||||
|
@ -27,19 +23,10 @@ void M5PaperComponent::setup() {
|
|||
gpio_hold_en(GPIO_NUM_2);
|
||||
gpio_hold_en(GPIO_NUM_5);
|
||||
}
|
||||
|
||||
adc_power_acquire();
|
||||
|
||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
||||
adc1_config_channel_atten(ADC1_GPIO35_CHANNEL, ADC_ATTEN_DB_11);
|
||||
this->_adc_chars = (esp_adc_cal_characteristics_t *)calloc(1, sizeof(esp_adc_cal_characteristics_t));
|
||||
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, BASE_VOLATAGE, this->_adc_chars);
|
||||
}
|
||||
|
||||
void M5PaperComponent::shutdown_main_power() {
|
||||
ESP_LOGE(TAG, "Shutting Down Power");
|
||||
adc_power_release();
|
||||
|
||||
if (ALLOW_ESPHOME_DEEP_SLEEP) {
|
||||
gpio_hold_dis(GPIO_NUM_2);
|
||||
gpio_hold_dis(GPIO_NUM_5);
|
||||
|
@ -47,25 +34,8 @@ void M5PaperComponent::shutdown_main_power() {
|
|||
this->main_power_pin_->digital_write(false);
|
||||
}
|
||||
|
||||
void M5PaperComponent::update() {
|
||||
uint32_t adc_raw_value = 0;
|
||||
for (uint16_t i = 0; i < ADC_FILTER_SAMPLE; i++)
|
||||
{
|
||||
adc_raw_value += adc1_get_raw(ADC1_GPIO35_CHANNEL);
|
||||
}
|
||||
|
||||
adc_raw_value = adc_raw_value / ADC_FILTER_SAMPLE;
|
||||
uint32_t millivolts = (uint32_t)(esp_adc_cal_raw_to_voltage(adc_raw_value, _adc_chars) / SCALE);
|
||||
|
||||
float voltage = static_cast<float>(millivolts) * 0.001f;
|
||||
|
||||
if (this->battery_voltage_ != nullptr)
|
||||
this->battery_voltage_->publish_state(voltage);
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
void M5PaperComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "Empty custom sensor");
|
||||
ESP_LOGCONFIG(TAG, "M5Paper");
|
||||
}
|
||||
|
||||
} //namespace m5paper
|
||||
|
|
|
@ -1,44 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/core/gpio.h"
|
||||
#include "esphome/core/automation.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include "driver/adc.h"
|
||||
#include <esp_adc_cal.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace m5paper {
|
||||
|
||||
class M5PaperComponent : public PollingComponent {
|
||||
class M5PaperComponent : public Component {
|
||||
void setup() override;
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; };
|
||||
/* Very early setup as takes care of powering other components */
|
||||
float get_setup_priority() const override { return setup_priority::BUS; };
|
||||
|
||||
public:
|
||||
void set_battery_power_pin(GPIOPin *power) { this->battery_power_pin_ = power; }
|
||||
void set_main_power_pin(GPIOPin *power) { this->main_power_pin_ = power; }
|
||||
void set_battery_voltage(sensor::Sensor *battery_voltage) { battery_voltage_ = battery_voltage; }
|
||||
void shutdown_main_power();
|
||||
public:
|
||||
void set_battery_power_pin(GPIOPin *power) { this->battery_power_pin_ = power; }
|
||||
void set_main_power_pin(GPIOPin *power) { this->main_power_pin_ = power; }
|
||||
void shutdown_main_power();
|
||||
|
||||
private:
|
||||
GPIOPin *battery_power_pin_{nullptr};
|
||||
GPIOPin *main_power_pin_{nullptr};
|
||||
sensor::Sensor *battery_voltage_{nullptr};
|
||||
|
||||
esp_adc_cal_characteristics_t *_adc_chars;
|
||||
private:
|
||||
GPIOPin *battery_power_pin_{nullptr};
|
||||
GPIOPin *main_power_pin_{nullptr};
|
||||
|
||||
};
|
||||
|
||||
template<typename... Ts> class PowerAction : public Action<Ts...>, public Parented<M5PaperComponent> {
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->shutdown_main_power(); }
|
||||
public:
|
||||
void play(Ts... x) override { this->parent_->shutdown_main_power(); }
|
||||
};
|
||||
|
||||
|
||||
} //namespace m5paper
|
||||
} //namespace esphome
|
288
m5paper.yaml
Normal file
288
m5paper.yaml
Normal file
|
@ -0,0 +1,288 @@
|
|||
esphome:
|
||||
name: ${device_id}
|
||||
name_add_mac_suffix: true
|
||||
project:
|
||||
name: "${project_name}"
|
||||
version: "${project_version}"
|
||||
includes:
|
||||
- render.h
|
||||
# on_boot:
|
||||
# - priority: -100.0
|
||||
# then:
|
||||
# - delay: ${default_update_interval}
|
||||
# - component.update: m5paper_display
|
||||
# - delay: 1s
|
||||
# - bm8563.apply_sleep_duration
|
||||
# - m5paper.shutdown_main_power
|
||||
# - deep_sleep.enter:
|
||||
# sleep_duration: 30s
|
||||
|
||||
esp32:
|
||||
board: m5stack-grey
|
||||
framework:
|
||||
type: arduino
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: components
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
baud_rate: 921600
|
||||
|
||||
psram:
|
||||
|
||||
api:
|
||||
|
||||
ota:
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
power_save_mode: "HIGH"
|
||||
fast_connect: true
|
||||
|
||||
globals:
|
||||
- id: material_icons_map
|
||||
type: std::map<std::string, std::string>
|
||||
restore_value: no
|
||||
initial_value: |
|
||||
{
|
||||
{"mdi-weather-night", ""},
|
||||
{"mdi-weather-cloudy", ""},
|
||||
{"mdi-weather-cloudy-alert", ""},
|
||||
{"mdi-weather-fog", ""},
|
||||
{"mdi-weather-hail", ""},
|
||||
{"mdi-weather-lightning-rainy", ""},
|
||||
{"mdi-weather-lightning", ""},
|
||||
{"mdi-weather-partly-cloudy", ""},
|
||||
{"mdi-weather-night-partly-cloudy", ""},
|
||||
{"mdi-weather-pouring", ""},
|
||||
{"mdi-weather-rainy", ""},
|
||||
{"mdi-weather-snowy-rainy", ""},
|
||||
{"mdi-weather-snowy", ""},
|
||||
{"mdi-weather-sunny", ""},
|
||||
{"mdi-weather-windy-variant", ""},
|
||||
{"mdi-weather-windy", ""},
|
||||
{"mdi-cloud-question", ""},
|
||||
{"mdi-thermometer", ""},
|
||||
{"mdi-water-percent", ""},
|
||||
{"mdi-molecule-co2", ""},
|
||||
{"mdi-wind-power-outline", ""},
|
||||
{"mdi-home-outline", ""},
|
||||
{"mdi-tree-outline", ""},
|
||||
{"mdi-gauge", ""},
|
||||
{"mdi-battery-high", ""},
|
||||
{"mdi-battery-medium", ""},
|
||||
{"mdi-battery-low", ""},
|
||||
{"mdi-battery-alert-variant-outline", ""},
|
||||
{"mdi-battery-charging-high", ""},
|
||||
{"mdi-battery-unknown", ""},
|
||||
{"mdi-shield-outline", ""},
|
||||
{"mdi-shield-home-outline", ""},
|
||||
{"mdi-shield-lock-outline", ""},
|
||||
{"mdi-shield-moon-outline", ""},
|
||||
{"mdi-shield-alert-outline", ""},
|
||||
{"mdi-molecule-co2", ""},
|
||||
{"mdi-radioactive", ""},
|
||||
{"mdi-numeric-0-circle-outline", ""},
|
||||
{"mdi-numeric-1-circle-outline", ""},
|
||||
{"mdi-numeric-2-circle-outline", ""},
|
||||
{"mdi-numeric-3-circle-outline", ""},
|
||||
{"mdi-numeric-4-circle-outline", ""},
|
||||
{"mdi-numeric-5-circle-outline", ""},
|
||||
{"mdi-numeric-6-circle-outline", ""},
|
||||
{"mdi-numeric-7-circle-outline", ""},
|
||||
{"mdi-numeric-8-circle-outline", ""},
|
||||
{"mdi-numeric-9-plus-circle-outline", ""},
|
||||
}
|
||||
|
||||
font:
|
||||
- file: 'gfonts://Roboto'
|
||||
id: normal_font
|
||||
size: 120
|
||||
- file: 'gfonts://Roboto'
|
||||
id: small_font
|
||||
size: 50
|
||||
- file: 'gfonts://Roboto'
|
||||
id: clock_font
|
||||
size: 260
|
||||
glyphs: "0123456789:"
|
||||
- file: "fonts/materialdesignicons-webfont.ttf"
|
||||
id: battery_font
|
||||
size: 40
|
||||
glyphs: [
|
||||
'', #mdi-battery-medium
|
||||
'', #mdi-battery-low
|
||||
'', # mdi-battery-high
|
||||
'', #mdi-battery-alert-variant-outline
|
||||
'', #mdi-battery-charging-high
|
||||
'', #mdi-battery-unknown
|
||||
]
|
||||
|
||||
spi:
|
||||
clk_pin: GPIO14
|
||||
mosi_pin: GPIO12
|
||||
miso_pin: GPIO13
|
||||
|
||||
i2c:
|
||||
sda: GPIO21
|
||||
scl: GPIO22
|
||||
|
||||
display:
|
||||
- platform: it8951e
|
||||
id: m5paper_display
|
||||
cs_pin: GPIO15
|
||||
reset_pin: GPIO23
|
||||
reset_duration: 5ms
|
||||
busy_pin: GPIO27
|
||||
rotation: 0
|
||||
reversed: False
|
||||
update_interval: never
|
||||
lambda: |-
|
||||
render(it);
|
||||
|
||||
touchscreen:
|
||||
- platform: gt911
|
||||
display: m5paper_display
|
||||
id: gt911_touchscreen
|
||||
interrupt_pin: GPIO36
|
||||
|
||||
switch:
|
||||
- platform: restart
|
||||
id: restart_switch
|
||||
name: ${device_name} restart
|
||||
- platform: gpio
|
||||
pin: 32
|
||||
name: "led"
|
||||
inverted: true
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
id: homeassistant_time
|
||||
on_time_sync:
|
||||
- bm8563.write_time
|
||||
- platform: bm8563
|
||||
id: rtc_time
|
||||
sleep_duration: 250s
|
||||
# on_time:
|
||||
# - seconds: /6
|
||||
# then:
|
||||
# - component.update: m5paper_display
|
||||
|
||||
script:
|
||||
- id: suspend
|
||||
then:
|
||||
- component.update: m5paper_display
|
||||
- delay: 2s
|
||||
- bm8563.apply_sleep_duration
|
||||
- m5paper.shutdown_main_power
|
||||
- delay: 30s
|
||||
- deep_sleep.enter:
|
||||
sleep_duration: ${sleep_duration}
|
||||
|
||||
interval:
|
||||
- interval: 1s
|
||||
then:
|
||||
- if:
|
||||
condition:
|
||||
and:
|
||||
# - lambda: "return !std::isnan(id(m5paper_battery_level).state);"
|
||||
- lambda: "return id(rtc_time).now().is_valid();"
|
||||
- lambda: "return !std::isnan(id(outside_temperature).state);"
|
||||
- lambda: "return !std::isnan(id(lounge_temperature).state);"
|
||||
then:
|
||||
- script.execute: suspend
|
||||
- interval: 3s
|
||||
then:
|
||||
- delay: 30s
|
||||
- script.execute: suspend
|
||||
|
||||
m5paper:
|
||||
battery_power_pin: GPIO5
|
||||
main_power_pin: GPIO2
|
||||
|
||||
sensor:
|
||||
- platform: adc
|
||||
disabled_by_default: true
|
||||
pin: GPIO35
|
||||
name: ${device_name} battery voltage
|
||||
id: m5paper_battery_voltage
|
||||
update_interval: ${default_update_interval}
|
||||
attenuation: 11db
|
||||
filters:
|
||||
- multiply: 2 #1,27272727
|
||||
- platform: sht3xd
|
||||
address: 0x44
|
||||
temperature:
|
||||
name: ${device_name} temperature
|
||||
id: m5paper_temperature
|
||||
device_class: "temperature"
|
||||
state_class: "measurement"
|
||||
icon: mdi:thermometer
|
||||
humidity:
|
||||
name: ${device_name} humidity
|
||||
id: m5paper_humidity
|
||||
device_class: "humidity"
|
||||
state_class: "measurement"
|
||||
icon: mdi:water-percent
|
||||
update_interval: ${default_update_interval}
|
||||
- platform: template
|
||||
name: ${device_name} battery level
|
||||
id: m5paper_battery_level
|
||||
unit_of_measurement: '%'
|
||||
device_class: "battery"
|
||||
state_class: "measurement"
|
||||
icon: mdi:battery-high
|
||||
update_interval: 20s
|
||||
lambda: |-
|
||||
constexpr float min_level = 3.52;
|
||||
constexpr float max_level = 4.15;
|
||||
return ((id(m5paper_battery_voltage).state - min_level) / (max_level - min_level)) * 100.00;
|
||||
filters:
|
||||
- clamp:
|
||||
min_value: 0
|
||||
max_value: 100
|
||||
- platform: homeassistant
|
||||
name: Outside temperature
|
||||
id: outside_temperature
|
||||
entity_id: sensor.ruuvitag_1a2d_temperature
|
||||
- platform: homeassistant
|
||||
name: Lounge temperature
|
||||
id: lounge_temperature
|
||||
entity_id: sensor.ruuvitag_963b_temperature
|
||||
- platform: homeassistant
|
||||
name: solar power
|
||||
id: solar_power
|
||||
entity_id: sensor.solax_pv1_power
|
||||
- platform: uptime
|
||||
id: uptime_sensor
|
||||
name: Uptime
|
||||
update_interval: 3s
|
||||
|
||||
binary_sensor:
|
||||
- platform: gpio
|
||||
name: ${device_name} right button
|
||||
id: right_button
|
||||
icon: mdi:gesture-tap-button
|
||||
pin:
|
||||
number: GPIO37
|
||||
inverted: true
|
||||
- platform: gpio
|
||||
name: ${device_name} left button
|
||||
icon: mdi:gesture-tap-button
|
||||
pin:
|
||||
number: GPIO39
|
||||
inverted: true
|
||||
- platform: gpio
|
||||
name: ${device_name} BTN/PWR button
|
||||
icon: mdi:gesture-tap-button
|
||||
pin:
|
||||
number: GPIO38
|
||||
inverted: true
|
||||
|
||||
deep_sleep:
|
||||
run_duration: 120s
|
||||
sleep_duration: ${sleep_duration}
|
||||
|
9
pipish.yaml
Normal file
9
pipish.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
substitutions:
|
||||
device_name: Pipish
|
||||
device_id: pipish
|
||||
project_name: juju.pipish
|
||||
project_version: "0.1"
|
||||
default_update_interval: "10s"
|
||||
sleep_duration: 10s
|
||||
|
||||
<<: !include m5paper.yaml
|
88
render.h
Normal file
88
render.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
inline int measure_width(const char* text, esphome::display::BaseFont& font) {
|
||||
int width;
|
||||
int x_offset;
|
||||
int baseline;
|
||||
int height;
|
||||
font.measure(text, &width, &x_offset, &baseline, &height);
|
||||
return width;
|
||||
}
|
||||
|
||||
inline int measure_height(const char* text, esphome::display::BaseFont& font) {
|
||||
int width;
|
||||
int x_offset;
|
||||
int baseline;
|
||||
int height;
|
||||
font.measure(text, &width, &x_offset, &baseline, &height);
|
||||
return height;
|
||||
}
|
||||
|
||||
inline void render_sensor(esphome::display::Display& it, int x, int y,
|
||||
float value, std::string unit,
|
||||
const std::string& label) {
|
||||
int normal_height = measure_height("X", id(normal_font));
|
||||
char formatted[20];
|
||||
if (std::isnan(value)) {
|
||||
it.print(x, y, &id(normal_font), TextAlign::TOP_CENTER, "--");
|
||||
} else {
|
||||
char value_text[20];
|
||||
if (std::abs(value) >= 1000) {
|
||||
unit = "k" + unit;
|
||||
value /= 1000;
|
||||
}
|
||||
if (std::abs(value) < 10) {
|
||||
sprintf(value_text, "%.1f", value);
|
||||
} else {
|
||||
sprintf(value_text, "%.0f", value);
|
||||
}
|
||||
int value_width = measure_width(value_text, id(normal_font));
|
||||
int unit_width = measure_width(unit.c_str(), id(small_font));
|
||||
int width = value_width + unit_width + 3;
|
||||
it.print(x - width / 2, y + normal_height, &id(normal_font),
|
||||
TextAlign::BASELINE_LEFT, value_text);
|
||||
it.print(x + width / 2 - unit_width, y + normal_height, &id(small_font),
|
||||
TextAlign::BASELINE_LEFT, unit.c_str());
|
||||
}
|
||||
it.print(x, y + normal_height + 3, &id(small_font), TextAlign::TOP_CENTER,
|
||||
label.c_str());
|
||||
}
|
||||
|
||||
inline void render(esphome::display::Display& it) {
|
||||
constexpr int kHeight = 540;
|
||||
constexpr int kWidth = 960;
|
||||
|
||||
// Clock
|
||||
it.strftime(25, 25, &id(clock_font), TextAlign::TOP_LEFT, "%H:%M",
|
||||
id(rtc_time).now());
|
||||
|
||||
int right_width = measure_width("123||", id(normal_font));
|
||||
render_sensor(it, kWidth - right_width / 2, kHeight * 0 / 10,
|
||||
id(outside_temperature).state, "°C", "Outside");
|
||||
render_sensor(it, kWidth - right_width / 2, kHeight * 3 / 10,
|
||||
id(lounge_temperature).state, "°C", "Lounge");
|
||||
render_sensor(it, kWidth - right_width / 2, kHeight * 6 / 10,
|
||||
id(solar_power).state, "W", "Solar");
|
||||
render_sensor(it, right_width / 2, kHeight * 6 / 10, id(uptime_sensor).state,
|
||||
"s", "Uptime");
|
||||
|
||||
static const struct {
|
||||
float level;
|
||||
std::string icon;
|
||||
} battery_levels[] = {
|
||||
{10, "mdi-battery-alert-variant-outline"},
|
||||
{40, "mdi-battery-low"},
|
||||
{70, "mdi-battery-medium"},
|
||||
{std::numeric_limits<float>::max(), "mdi-battery-high"},
|
||||
};
|
||||
|
||||
// Battery
|
||||
float battery_level = id(m5paper_battery_level).state;
|
||||
if (!std::isnan(battery_level)) {
|
||||
for (const auto& level : battery_levels) {
|
||||
if (battery_level <= level.level) {
|
||||
it.print(910, 10, &id(battery_font),
|
||||
id(material_icons_map)[level.icon].c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue