Compare commits

...

362 Commits

Author SHA1 Message Date
Jesse Hills
808ce6eecb Merge pull request #1548 from esphome/bump-1.16.2
1.16.2
2021-02-20 19:58:48 +13:00
Jesse Hills
665d0fd759 Bump version to v1.16.2 2021-02-20 19:29:52 +13:00
Jesse Hills
c519c02de8 Fix safe mode ota flashing under certain configurations (#1534)
* Fix safe mode ota flashing under certain configurations by allowing the arduino loop to run instead of while(true)

* rename to should_enter_safe_mode

* Fix line length
2021-02-20 19:29:52 +13:00
Samuel Sieb
eacac78099 Add reverse_enable for max7219 (#1489) 2021-02-20 19:29:52 +13:00
Kris
a925036ff8 Added Waveshare 2.90inch V2 e-ink display (#1538) 2021-02-20 19:29:52 +13:00
SenexCrenshaw
1468293f3e fix DHT auto_detect check (#1536) 2021-02-20 19:29:52 +13:00
Jesse Hills
925a992d1b Merge pull request #1531 from esphome/bump-1.16.1
1.16.1
2021-02-14 15:04:43 +13:00
Jesse Hills
61ecbe4273 Bump version to v1.16.1 2021-02-14 10:01:22 +13:00
Keith Burzinski
65c7e27a43 MCP230xx open drain interrupt pins (#1243) 2021-02-14 10:01:21 +13:00
Frank Bakker
57b56010da Added energy sensor to hlw8012 (#1198) 2021-02-14 10:01:21 +13:00
SenexCrenshaw
ef89249019 Fixed ST7735 transfer_byte to write_byte without miso (#1529) 2021-02-14 10:01:21 +13:00
Klarstein
bc64cf3e47 Update Dockerfile health check timings (#1517) 2021-02-14 10:01:21 +13:00
Jesse Hills
def70dde72 Fix PN532 SPI communication (#1511) 2021-02-14 10:01:21 +13:00
Jesse Hills
d238e06f86 Merge pull request #1509 from esphome/bump-1.16.0
1.16.0
2021-02-04 02:56:32 +13:00
Jesse Hills
2fc59ecc30 Bump version to v1.16.0 2021-02-03 21:19:42 +13:00
Jesse Hills
0047d24698 Merge pull request #1507 from esphome/bump-1.16.0b8
1.16.0b8
2021-02-03 13:17:40 +13:00
Jesse Hills
89a89e1785 Bump version to v1.16.0b8 2021-02-03 12:33:30 +13:00
Guillermo Ruffino
1952d275f7 RC522 increased retry loop count (#1506) 2021-02-03 12:33:29 +13:00
hcoohb
043095b605 fix esp8266 remote_transmitter using incorrect timings (#1465)
* replace delay by delayMicroseconds in delay_microseconds_accurate

* Use delay(0) to let wifi and os function run

* Linting

* Remove unneeded delayMicroseconds, keep it for low usec

* Avoid micros() overflow issue
2021-02-03 12:33:29 +13:00
Jesse Hills
431d3578a5 Merge pull request #1504 from esphome/bump-1.16.0b7
1.16.0b7
2021-02-01 18:42:33 +13:00
Jesse Hills
5f02d86841 Bump version to v1.16.0b7 2021-02-01 15:34:45 +13:00
Jesse Hills
a7ec57d4be Allow SCD30 sensors to be optional (#1502) 2021-02-01 15:34:44 +13:00
Jesse Hills
1ea5cc497f Merge pull request #1497 from esphome/bump-1.16.0b6
1.16.0b6
2021-01-27 23:19:17 +13:00
Jesse Hills
b601cf6bc6 Bump version to v1.16.0b6 2021-01-27 23:04:20 +13:00
nikito7
5057caa7fc Add support for MHO-C401 (#1486)
Committer: nikito7

Co-authored-by: vevsvevs <v-v@mail.ru>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: nikito7 <root@vbox.lan>
2021-01-27 23:04:20 +13:00
Klarstein
95bef53d37 Add docker healthcheck (#1492) 2021-01-27 23:04:20 +13:00
Paul Nicholls
ea019a057b Add support for string-type Tuya datapoints (#1488) 2021-01-27 23:04:20 +13:00
Jesse Hills
b860a317b9 Merge pull request #1495 from esphome/bump-1.16.0b5
1.16.0b5
2021-01-26 14:45:53 +13:00
Jesse Hills
9591c903f7 Bump version to v1.16.0b5 2021-01-26 13:39:43 +13:00
SenexCrenshaw
65fbb8bc60 SPI wasnt being disabled after display update (#1493) 2021-01-26 13:39:42 +13:00
Philipp Tölke
97428f2ba2 Make fade_to*, lighten, and darken const (#1450) 2021-01-26 13:39:42 +13:00
Zixuan Wang
9ab6a7b7ff Improve ccs811 precision (#1428) 2021-01-26 13:39:42 +13:00
Florian Mösch
e2ad6fe3d8 rename read/write to read/time/write_time (#1468) 2021-01-26 13:39:42 +13:00
Florian Mösch
6781d08c9b time sync notification (#1442)
* add on_time_sync trigger

* cleanup lint

* fix review remark (sntp didn't trigger callbacks)
2021-01-26 13:39:42 +13:00
Jesse Hills
828f7946ea Merge pull request #1475 from esphome/bump-1.16.0b4
1.16.0b4
2021-01-17 17:20:36 +13:00
Jesse Hills
23c663d5d4 Bump version to v1.16.0b4 2021-01-17 17:06:38 +13:00
David Zovko
6a99789c92 Inkplate 6 support for ESPHome (#1283)
* Add Inkplate 6 support

Inkplate 6 is e-paper display based on ESP32. This commit adds support for integrating Inkplate 6 into the ESPHome. Find more info here: inkplate.io

* Greyscale working

* Update inkplate.h

* Fix formatting

* Formatting

* Update esphome/components/inkplate6/display.py

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>

* Update esphome/components/inkplate6/display.py

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>

* Fix some lint errors
Ignore some lint errors
Only allow on ESP32

* Update the codeowners file

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2021-01-17 17:06:38 +13:00
Jesse Hills
52e13164b4 Add NDEF reading and writing to PN532 (#1351) 2021-01-17 17:06:38 +13:00
SenexCrenshaw
28f2582256 Updated Mcp3008 to support reference_voltage and voltage_sampler::VoltageSampler (#1387)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2021-01-17 17:06:37 +13:00
Florian Mösch
652f6058d1 make time components polling components (#1443)
* make real time clock components polling components

* add test
2021-01-17 17:06:37 +13:00
Guillermo Ruffino
717aab7c8b Add rc522 i2c (#1432)
* split to spi and i2c

* fix binary_sensor

* i2c comms ready

* fix rc522_spi binary sensor compat

* lint

* lint

* add test and codeowners

* fix refactor
2021-01-17 17:06:37 +13:00
dependabot[bot]
5e799b5284 Bump pytest-mock from 3.3.1 to 3.5.1 (#1458)
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.3.1 to 3.5.1.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.3.1...v3.5.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-17 17:06:37 +13:00
mmanza
9f36b25d4e Whirlpool ac (#1467)
* Checksum calc change

* first checksum change for MODEL_DG11J1_3A
2021-01-17 17:06:37 +13:00
Jesse Hills
c8058e9636 Merge pull request #1463 from esphome/bump-1.16.0b3
1.16.0b3
2021-01-12 09:57:51 +13:00
Jesse Hills
f2474c5c45 Bump version to v1.16.0b3 2021-01-12 09:42:19 +13:00
Guillermo Ruffino
7acc36d39d Revert esptool to 2.8 (#1460)
Fixes https://github.com/esphome/issues/issues/1702
2021-01-12 09:42:19 +13:00
mknjc
b01db991a5 API: copy the data to send into the tcp internal buffer (#1455)
Without the flag lwip only holds a reference to the supplied buffers and the reference must be valid until the tcp ack is received. This can't be guaranteed for stack allocated buffers
2021-01-12 09:42:19 +13:00
Jesse Hills
8c849b9002 Merge pull request #1459 from esphome/bump-1.16.0b2
1.16.0b2
2021-01-11 21:08:18 +13:00
Jesse Hills
6a0d4cb5a9 Bump version to v1.16.0b2 2021-01-11 20:10:36 +13:00
mknjc
72002ce70e Rotary Encoder: Don't call callbacks in the isr (#1456) 2021-01-11 20:10:35 +13:00
Dan Jackson
c67539cf5b Add encode_uint32 method (#1427) 2021-01-11 20:10:35 +13:00
Florian Mösch
dcd3d2084d DS1307 real time clock component (#1441)
* initial support for DS1307 real time clock

* add simple test, make sync functions public

* cleanup lint

* add sync to/from rtc actions

* changes action names

* Update esphome/components/ds1307/ds1307.cpp

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>

* Update esphome/components/ds1307/time.py

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>

* fix suggested change

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
2021-01-11 20:10:35 +13:00
Alex
585bb6dac8 fix safe_mode (#1421)
* Deprioritize automations

Ensures safe mode is loaded before any automations are ran

* Fix lint
2021-01-11 20:10:35 +13:00
Jesse Hills
cac3055261 Merge pull request #1452 from esphome/bump-1.16.0b1
1.16.0b1
2021-01-09 07:48:27 +13:00
Jesse Hills
6f7e6cc944 Bump version to v1.16.0b1 2021-01-09 00:05:18 +13:00
Jesse Hills
0a841fcc50 Merge branch 'dev' into bump-1.16.0b1 2021-01-09 00:04:33 +13:00
Fractal147
3c64c9b0e9 Fix stepper half half step mode (#1397)
* Fixed half half step mode

Half step mode originally had second and third steps mixed up for output A.
https://github.com/esphome/issues/issues/1655

* Updated half step mode to have no branching

Code based off comments in PR: https://github.com/esphome/esphome/pull/1397#issuecomment-739413973

* removed variable declarations in the switch/case

Oops. No explicit declarations.
Rearranged to be tidier, same output sequence.

* Fixed typo bracket

Minor typo fixed - logic complete to do branchless half stepping.

* Format the brackets to satisfy clang
2021-01-08 00:17:41 -03:00
rradar
34df25da39 Update __init__.py (#1454)
:cherry: picked from esphome/esphome@32a4680 branch (fix-sn74hc595-optional-oe-pin) by @OttoWinter
2021-01-08 00:12:55 -03:00
dependabot[bot]
9586fb95d1 Bump platformio from 5.0.3 to 5.0.4 (#1444)
Bumps [platformio](https://github.com/platformio/platformio) from 5.0.3 to 5.0.4.
- [Release notes](https://github.com/platformio/platformio/releases)
- [Changelog](https://github.com/platformio/platformio-core/blob/develop/HISTORY.rst)
- [Commits](https://github.com/platformio/platformio/compare/v5.0.3...v5.0.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-05 13:16:15 -03:00
dependabot[bot]
3ee6348e41 Bump pytest from 6.1.2 to 6.2.1 (#1422)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.1.2 to 6.2.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.1.2...6.2.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-03 18:10:59 -03:00
dependabot[bot]
543f2c8152 Bump pytz from 2020.4 to 2020.5 (#1430)
Bumps [pytz](https://github.com/stub42/pytz) from 2020.4 to 2020.5.
- [Release notes](https://github.com/stub42/pytz/releases)
- [Commits](https://github.com/stub42/pytz/compare/release_2020.4...release_2020.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-03 18:10:33 -03:00
Andreas Hergert
16d11be213 added slow mode and detach time to servo (#1413)
* added slow mode and detach time to servo

* tidy

* and again tidy

* add change requests

* tidy

* tidy

* tidy

Co-authored-by: Andreas Hergert <andreas.hergert@otrs.com>
2021-01-03 17:57:30 -03:00
M95D
e49b568fd4 rc_switch: Fix Sync signal sent after the code. (#1426) 2020-12-30 23:11:46 +13:00
Klarstein
22ab830ff3 Expose port 6052 in Dockerfile (#1437) 2020-12-30 22:58:09 +13:00
Keith Burzinski
095d3181cd SSD1322 display support (#1405) 2020-12-30 22:52:41 +13:00
Keith Burzinski
9aa14a2e83 Add full SSD1327 display support (#1406) 2020-12-30 22:48:23 +13:00
acshef
ac15ce576b Added "ESPHOME_NOGITIGNORE" env var to prevent .gitignore creation; moved env vars to consts (#1425) 2020-12-22 10:19:26 +13:00
Daniel Schramm
498b59e998 Canbus + MCP2515 including ExtID support (#1384) 2020-12-22 08:27:20 +13:00
dependabot[bot]
63c420254a Bump esptool from 2.8 to 3.0 (#1357) 2020-12-18 10:07:29 -03:00
richardweinberger
765e641d08 Fix mDNS webserver port and expose prometheus service (#1389)
* Expose right webserver port using mDNS.

80 is the default value but can be changed in the config file.
Add a new define for the port.

Signed-off-by: Richard Weinberger <richard@nod.at>

* Expose prometheus service via mDNS

That way prometheus auto discovery features can find us.

Signed-off-by: Richard Weinberger <richard@nod.at>
2020-12-14 17:14:38 -03:00
dependabot[bot]
be16d10b7d Bump tornado from 6.0.4 to 6.1 (#1353)
Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.0.4 to 6.1.
- [Release notes](https://github.com/tornadoweb/tornado/releases)
- [Changelog](https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst)
- [Commits](https://github.com/tornadoweb/tornado/compare/v6.0.4...v6.1.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-14 16:17:31 -03:00
Marcel Feix
4b808611e9 Add GIF Animation Support (#1378)
* Adding GIF Animation Support

* CLang tidy correction

* Adding Codeowner
2020-12-14 13:17:16 -03:00
gitolicious
7afe202e20 Run task for VS Code (#1361)
* Add VS Code task to run dashboard

* Includ VS Code tasks in git

* Set problemMatcher to none
2020-12-13 16:24:26 -03:00
Ryan Mounce
039810eef3 Fix Tuya initialisation regression (#1408) 2020-12-07 19:30:55 +13:00
dependabot[bot]
ff43b45113 Bump pyserial from 3.4 to 3.5 (#1394)
Bumps [pyserial](https://github.com/pyserial/pyserial) from 3.4 to 3.5.
- [Release notes](https://github.com/pyserial/pyserial/releases)
- [Changelog](https://github.com/pyserial/pyserial/blob/master/CHANGES.rst)
- [Commits](https://github.com/pyserial/pyserial/compare/v3.4...v3.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-07 19:15:54 +13:00
SenexCrenshaw
7cd4c3bdd3 MCP23SXX I/O Expander - SPI (#1068)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2020-12-07 06:43:55 +13:00
Nikolay Vasilchuk
c12c9e97c2 HTTP Request fix reusing connections. (#1383) 2020-12-04 07:37:00 +13:00
Michel Marti
b3169deda7 scd30: Allow setting temperature offset (#1400) 2020-12-04 07:21:10 +13:00
stubs12
0ea41e2f71 Add option to suppress embedded MCU updates on certain datapoints (#1396) 2020-12-03 17:38:17 +13:00
Alex
3afb564a48 Configurable OTA Safe Mode (#1393) 2020-12-02 11:41:39 +13:00
SenexCrenshaw
7ff3f752e2 New display ST7735 (#1066)
* Initial Commit - ST7735

* Updated for CI checks

* Updated for travis build

* Travis fixes

* Travis line too long

* Travis fixes

* Fixed up travis format issues

* Travis Fixes

* Initial Commit - ST7735

* Updated for CI checks

* Updated for travis build

* Travis fixes

* Travis line too long

* Travis fixes

* Fixed up travis format issues

* Travis Fixes

* Update to new color API and added test

* Check fixes

* Fixed sid length in test

* Cleaned up whitespaces

* kbx81 recommended fixes

* test fix

* Fixes of fixes

* Fixed test1.yaml

* Fixed test1.yaml

* Changed digital pin #s to gpio

* Updated to match kbx's color names

* Typo for ST7735_INITR_MINI_160X80

* Updated 8bit color space code
Added to_rgb_332 to color.h
fixed typo

* Added in to_rgb_332,to_bgr_332, rgb_332to_rgb_556 and a more generic scale

* Fixed MADCTL

* Fixp MADCTL

* Implemented usrbgr option
updated color to support 332 bgr conversion
typo fix

* Updated to_bgr_332

* Fix up for clang

* FIx up init code. type in buffer caused overrun

* fixup protected names

* typos

* Matched use_bgr to its conf

* color.h red fix in bgr_233to_rgb_565

* Fix ST7735_INITR_MINI_160X80

* Renamed bgr_233to_bgr_565 to match its function
Color space leak in bgr_233to_bgr_565.
cleaned up init code for displays.

* Fix

* clang fix

* Started Color Conversion

* Added various bit color functions
add triadto

* lint changes

* Various fixes

* Various formatting fixes. Wish my checks worked!

* Updated color api to support different formats
removed to_rgb_565

* lint clang fixes

* Test1 fix

* test1.yaml fix

* fixed 565 in ILI9341Display

* Added CodeOwners

* Updated CODEOWNERS

* changed to to332 and to565

* Waiting for color.h changes

* Stage changes

* Removed all changes except this driver

* Moved color functions into driver

* lint changes

* Lint and removed unrelated display driver changes

* Lint changes

* Initial Commit - ST7735

* Updated for CI checks

* Updated for travis build

* Travis fixes

* Travis line too long

* Travis fixes

* Fixed up travis format issues

* Travis Fixes

* Initial Commit - ST7735

* Updated for CI checks

* Updated for travis build

* Travis fixes

* Travis line too long

* Travis fixes

* Fixed up travis format issues

* Travis Fixes

* Update to new color API and added test

* Check fixes

* Fixed sid length in test

* Cleaned up whitespaces

* kbx81 recommended fixes

* test fix

* Fixes of fixes

* Fixed test1.yaml

* Fixed test1.yaml

* Changed digital pin #s to gpio

* Updated to match kbx's color names

* Typo for ST7735_INITR_MINI_160X80

* Updated 8bit color space code
Added to_rgb_332 to color.h
fixed typo

* Added in to_rgb_332,to_bgr_332, rgb_332to_rgb_556 and a more generic scale

* Fixed MADCTL

* Fixp MADCTL

* Implemented usrbgr option
updated color to support 332 bgr conversion
typo fix

* Updated to_bgr_332

* Fix up for clang

* FIx up init code. type in buffer caused overrun

* fixup protected names

* typos

* Matched use_bgr to its conf

* color.h red fix in bgr_233to_rgb_565

* Fix ST7735_INITR_MINI_160X80

* Renamed bgr_233to_bgr_565 to match its function
Color space leak in bgr_233to_bgr_565.
cleaned up init code for displays.

* Fix

* clang fix

* Started Color Conversion

* Added various bit color functions
add triadto

* lint changes

* Various fixes

* Various formatting fixes. Wish my checks worked!

* Updated color api to support different formats
removed to_rgb_565

* lint clang fixes

* Test1 fix

* test1.yaml fix

* fixed 565 in ILI9341Display

* Added CodeOwners

* Updated CODEOWNERS

* changed to to332 and to565

* Waiting for color.h changes

* Stage changes

* Removed all changes except this driver

* Moved color functions into driver

* lint changes

* Lint and removed unrelated display driver changes

* Lint changes

* Updated with latest color api

* pulled from origin

* Updated for color.h changes

* pulled test1 from dev

* Added test
2020-11-23 14:37:43 -03:00
SenexCrenshaw
d821ead92a Formatted test yaml files (#1382) 2020-11-19 23:59:19 -03:00
Nikolay Vasilchuk
e42ce64127 Fixed logger broken by colorama (#1385) 2020-11-19 19:39:16 -03:00
SenexCrenshaw
9d2b0b4e03 Added 332 color conversion and RGB/BGR/GRB formats (#1381) 2020-11-20 09:38:00 +13:00
Keith Burzinski
b5e6ae0d69 Add kbx81 to CODEOWNERS (#1380) 2020-11-18 19:46:22 +13:00
Keith Burzinski
08f1eac8b2 SSD1331 display support (#1244) 2020-11-18 19:34:53 +13:00
Samuel Sieb
6ed3da33a2 add CODEOWNER for new ezo component (#1379)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2020-11-18 15:57:25 +13:00
MoA
a9a00f139b Add climate.hitachi_ac344 (#1336)
* Add climate.hitachi_ac344

* Add Hitachi AC344 Climate IR test

* Fixes unhandled switch-case in fan-mode

* Fixes logging format

* Fixes file mode

* Lint clang-tidy

* Lint clang-tidy

* Static cast float to uint8
git push

* Remove comment and debug code

* Change log verbosity to VV
2020-11-17 22:05:12 -03:00
dependabot[bot]
63d8071dbd Bump platformio from 5.0.2 to 5.0.3 (#1372)
Bumps [platformio](https://github.com/platformio/platformio) from 5.0.2 to 5.0.3.
- [Release notes](https://github.com/platformio/platformio/releases)
- [Changelog](https://github.com/platformio/platformio-core/blob/develop/HISTORY.rst)
- [Commits](https://github.com/platformio/platformio/compare/v5.0.2...v5.0.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-17 13:15:16 -03:00
Samuel Sieb
d20caa9d60 add support for EZO sensor circuits (#1239)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2020-11-17 22:01:42 +13:00
Marcos Pérez Ferro
7e40d4246c Adding ADE7953 irq_pin (#1359) 2020-11-16 09:30:14 +13:00
0hax
5a2b14cfa4 components: teleinfo: electrical counter information. (#1108)
Signed-off-by: 0hax <0hax@protonmail.com>
Co-authored-by: Otto Winter <otto@otto-winter.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2020-11-16 07:08:19 +13:00
Michel Marti
f2d218e5ad scd30: Allow setting ambient pressure compensation (#1365) 2020-11-16 07:03:08 +13:00
Samuel Sieb
b493d5bba5 Add bounds check for X (#1371)
Avoid crash if a draw goes to a negative X position.
2020-11-12 21:55:42 +13:00
Yaroslav
c9055f2aef Allow Tuya climate temperature_multiplier to be current/target multiplier (#1345)
* Separate temperature_multiplier to current/target multiplier

* Apply suggestions from code review

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2020-11-12 06:31:35 +13:00
Yaroslav
9fed7cab5f Add support for Tuya MCU 0x1C (obtain local time) (#1344)
* Fix some Tuya devices not handling commands sent without delay

* Also do not report WiFi status if MCU does not support it

* Support Tuya MCU 0x1c command (obtain local time)

* Use #ifdef USE_TIME to handle optional dependency on RTC

* Rename Tuya clock config variable to time to be consistent with the codebase

* Add tuya time configuration to test4
2020-11-11 11:31:28 +13:00
dependabot[bot]
eb5c4b7c4f Bump colorlog from 4.4.0 to 4.6.2 (#1367)
Bumps [colorlog](https://github.com/borntyping/python-colorlog) from 4.4.0 to 4.6.2.
- [Release notes](https://github.com/borntyping/python-colorlog/releases)
- [Commits](https://github.com/borntyping/python-colorlog/compare/v4.4.0...v4.6.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-10 12:33:15 -03:00
Rob de Jonge
2ab3534a4b Correcting Hertz symbol (#1364)
Changing to the global standard as per https://en.wikipedia.org/wiki/Hertz.
2020-11-09 21:20:19 +13:00
Vc
9816e677a6 add Ili9341 display (#1233)
* setup ili9341 framework
used epaper-waveshare as start

* first version working

* added models for now only M5Stack

* get_buffer_length is huge

* fill, low/high watermark, buffer tests failed.
RAM is to small for ili9341 16 bit color mode

* removed high/low watermark debug log

* added standard 2.4" TFT model

* code cleanup

* make ledpin optional
busy pin is not needed

* make bufer 1 byte to avoid the
buffer allocation error

* gitignore

* added backlight pin to dump_config

* huge speed increase
8bit color framebuffer (256 colors)
lo and high watermark for drawing to screen

* fix for images

* higher spi data rates

* Set spi data rate to 40Mhz Experimental

* fixed: formatting
fixed: the last row and column being trimmed
fixed: namings

* Update the code to use Color class

* fixed minor color things

* fixed linting

* #patch minor fixes

* fix gitignore too

* Update esphome/components/ili9341/ili9341_display.cpp

Co-authored-by: Oleg <epushiron+github@gmail.com>

* reverting the changes as it's being fixed in PR-1241

Co-authored-by: Michiel van Turnhout <qris.online@gmail.com>
Co-authored-by: Michiel van Turnhout <m.vanturnhout@exxellence.nl>
Co-authored-by: Oleg <epushiron+github@gmail.com>
2020-11-08 22:53:35 -03:00
Daniel Hyles
fc01a70b65 Hbridge christmas light (#1251)
* Hbridge Christmas light component

Can be used for Christmas lights that use 2 wires to run 2 different strings of lights using a hbridge driver.

* Add Test

NOTE: I am unable to test this via the docker image

* Update hbridge_light_output.h

* Update hbridge_light_output.h

* Update hbridge_light_output.h

* Update light.py

* Fixed duty as white value bug fixed

* lint changes

* Name case change

* thanks lint
2020-11-08 14:46:34 +13:00
la7dja
7221337442 Support I2C transactions with combined reads and writes (#996)
* Support I2C transactions with combined reads and writes

* Add optional send_stop parameter to I2CComponent::raw_end_transmission

* Add convenience methods to I2CDevice

* clang-format

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2020-11-06 17:09:28 +13:00
Connor Prussin
051a1e4772 Add a datapoint to sync the Tuya MCU minimum brightness (#1347)
The Tuya MCU keeps its own internal minimum brightness setting.  This value may
not match the minimum brightness setting for ESPHome, leading to some issues:

1. Dimming is limited--on some devices the default minimum is as high as 10%,
meaning the dimmest ESPHome will go is still quite bright.

2. HA will allow a user to set a value below the MCU minimum, but the MCU will
reject it and keep the previous setting, so the UI is confusing.

This PR adds a setting to configure the datapoint for setting the MCU minimum
brightness.  If the setting is set, then ESPHome will synchronize the MCU's
minimum brightness with the one configured for ESPHome on startup.
2020-11-06 12:53:25 +13:00
dependabot[bot]
274741a9d5 Bump pytz from 2020.1 to 2020.4 (#1354)
Bumps [pytz](https://github.com/stub42/pytz) from 2020.1 to 2020.4.
- [Release notes](https://github.com/stub42/pytz/releases)
- [Commits](https://github.com/stub42/pytz/compare/release_2020.1...release_2020.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-04 07:11:13 +13:00
dependabot[bot]
25c01adf51 Bump voluptuous from 0.11.7 to 0.12.0 (#1296)
Bumps [voluptuous](https://github.com/alecthomas/voluptuous) from 0.11.7 to 0.12.0.
- [Release notes](https://github.com/alecthomas/voluptuous/releases)
- [Changelog](https://github.com/alecthomas/voluptuous/blob/master/CHANGELOG.md)
- [Commits](https://github.com/alecthomas/voluptuous/commits/v0.12.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-04 07:08:40 +13:00
dependabot[bot]
bf2d54c3ef Bump pytest from 6.1.1 to 6.1.2 (#1342)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.1.1 to 6.1.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.1.1...6.1.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-04 07:06:42 +13:00
Alexander Pohl
49cb8fd9d3 Add support for ATC_MiThermometer (#1291)
* Add support for additional Xiaomi BLE sensors (#1027)

* Revert "Add support for additional Xiaomi BLE sensors (#1027)"

This reverts commit b2723830f4.

* initial ATC Mithermometer component

* removed references to xiaomi_ble

* temp, humi and batt in % working, todo: battery in mV

* report battery level in volt

* report battery level again in percent

* Add files via upload

* add ATC Mithermometer component

* remove some comments

* fix travis ci build issues

* mark codeowner, make functions protected

* add newlines, remove spaces

* two lines after function or class definition

* update codeowners

* Bump flake8 from 3.8.3 to 3.8.4

Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.8.3 to 3.8.4.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.8.3...3.8.4)

Signed-off-by: dependabot[bot] <support@github.com>

* Add files via upload

* Bump pytest from 6.0.2 to 6.1.1

Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.2 to 6.1.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.2...6.1.1)

Signed-off-by: dependabot[bot] <support@github.com>

* add ATC battery voltage to test2.yaml

* fix lint-python

* Bump colorlog from 4.2.1 to 4.4.0

Bumps [colorlog](https://github.com/borntyping/python-colorlog) from 4.2.1 to 4.4.0.
- [Release notes](https://github.com/borntyping/python-colorlog/releases)
- [Commits](https://github.com/borntyping/python-colorlog/compare/v4.2.1...v4.4.0)

Signed-off-by: dependabot[bot] <support@github.com>

* Bump voluptuous from 0.11.7 to 0.12.0

Bumps [voluptuous](https://github.com/alecthomas/voluptuous) from 0.11.7 to 0.12.0.
- [Release notes](https://github.com/alecthomas/voluptuous/releases)
- [Changelog](https://github.com/alecthomas/voluptuous/blob/master/CHANGELOG.md)
- [Commits](https://github.com/alecthomas/voluptuous/commits/v0.12.0)

Signed-off-by: dependabot[bot] <support@github.com>

* restore requirements

* move codeowner above dependencies

* Revert "restore requirements"

This reverts commit 3c9fd8b421.

* Revert "Bump voluptuous from 0.11.7 to 0.12.0"

This reverts commit 8eb0dba1c3.

* Revert "Bump flake8 from 3.8.3 to 3.8.4"

This reverts commit 20952632db.

* Revert "Bump colorlog from 4.2.1 to 4.4.0"

This reverts commit 87bbf95d86.

* Revert "Bump pytest from 6.0.2 to 6.1.1"

This reverts commit 1b6ed80431.

Co-authored-by: vevsvevs <v-v@mail.ru>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-04 06:36:11 +13:00
Dimitris Zervas
e536316e3d Add contrast option to PCD8544 (#1348)
* Add contrast option to PCD8544. Closes #1519

* Minor fixes as instructed by @jesserockz
2020-11-03 10:05:20 +13:00
Jesse Hills
a6c46eb8e5 Adds support for RF Bridge advanced codes (#1246)
* WIP: Advanced commands for portisch firmware

* Fix string code sending

* clang formatting

* Add new rf_bridge functions to test

* Add advanced code received trigger

* Fix copy-paste mistake in the advanced sending

* Fix log message to be consistent

* clang

* Remove extra +
2020-11-03 07:34:29 +13:00
dependabot[bot]
1a270374e0 Bump platformio from 5.0.1 to 5.0.2 (#1355)
Bumps [platformio](https://github.com/platformio/platformio) from 5.0.1 to 5.0.2.
- [Release notes](https://github.com/platformio/platformio/releases)
- [Changelog](https://github.com/platformio/platformio-core/blob/develop/HISTORY.rst)
- [Commits](https://github.com/platformio/platformio/compare/v5.0.1...v5.0.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-02 09:45:28 -03:00
Jesse Hills
e73eafbd88 Move CONF_CONTRAST to const.py (#1352) 2020-11-02 21:25:41 +13:00
Jesse Hills
9fc3e05b76 Update actions to move away from set-env (#1349) 2020-11-02 11:49:08 +13:00
San
31c604331c add dither option for image processing (#1317)
* [Image] add dither option for image processing

* fix import order

* revert import location
and hardcode two dither method

* fix format
2020-11-02 07:54:13 +13:00
Nico B
3fcdaaefe0 add FastLED YAML option for data rate (#1338)
* fix: FastLED SPI_DATA_RATE being truncated to 8 bits

FastLED expects SPI_DATA_RATE as an uint32_t, but we had it as uint8_t.
Fix that to avoid the data rate being truncated.

* fastled: allow specifying data rate

Previously, we've just taken the default data rate from FastLED.
However, that does not always work properly. In my case, I had a
slow level shifter that couldn't keep up with the 1 MHz data
rate default for WS2801. Long cabling might also be a reason why
one might want to reduce the data rate.

This will add a new optional "data_rate" config option where one
may specify the desired data rate as a frequency:

  light:
    - platform: fastled_spi
      chipset: WS2801
      data_pin: GPIO23
      clock_pin: GPIO22
      data_rate: 500kHz
      num_leds: 178
2020-11-02 07:45:21 +13:00
Jesse Hills
20dd744680 Add on_clockwise and on_anticlockwise triggers to rotary encoder (#1330) 2020-11-02 06:24:26 +13:00
Frank Bakker
e4636b99f7 Pulse_counter measure total pulses (#1173)
* Draft Pulse_count_total

* Added check if Total sensor is present

* fix lint errors

* fix lint

* Update esphome/components/pulse_counter/sensor.py

Co-authored-by: Otto Winter <otto@otto-winter.com>

Co-authored-by: Otto Winter <otto@otto-winter.com>
2020-11-01 20:45:26 +13:00
Tom Price
10e7abb579 Add support for WPA2-EAP enterprise WiFi to ESP8266s. (#1332)
* Add support for WPA2-EAP enterprise WiFi to ESP8266s.

This is fundamentally the same as on ESP32s only with different function names.

Update config checker to remove requirement for ESP32 for EAP authentication.

* Fix indent for clang
2020-11-01 20:40:18 +13:00
Alone
d3f03b7acb add illuminance for xiaomi_mjyd02yla (#1299)
* add illuminance for xiaomi_mjyd02yla

* add illuminance for xiaomi_mjyd02yla
2020-11-01 17:24:41 +13:00
Rob Deutsch
7e53fc9d6a Fixed CLIMATE_SWING_HORIZONTAL typo (#1340) 2020-10-31 20:27:40 -03:00
Jesse Hills
0059a6de46 Pn532 upgrades (#1302)
* Move pn532 -> pn532_spi
Add pn532_i2c

* Update i2c address

* Always wait for ready byte before reading

* Generalise the pn532 a bit more so less code in i2c and spi implementations

* clang

* Add pn532_i2c to test1

* Try to get setup working

* Fixes

* More updates

* Command consts

* A few upgrades

* Change text back to include 'new'

* Fix data reading
2020-10-31 19:55:48 -03:00
Jesse Hills
22e1758d5b Add new codeowners (#1335)
* Add codeowner for tmp102

* Add codeowner for mcp9808
2020-10-28 06:56:41 +13:00
Guillermo Ruffino
59cdc32970 Add rc522 (#1298)
* wip

* first working

* feat complete

* add CODEOWNERS

* renamed to spi, reset optional

* add test

* fix CODEOWNERS
2020-10-27 12:41:57 +13:00
Harald Nagel
adb51cf733 Add MCP9808 temperature sensor (#1169)
* Add MCP9808 temperature sensor

* Change from component to sensor; code fixes

- Change from component to sensor
- Change magic numbers to constants

* Fix incorrect logging levels

* Add precision to debug log

* Fix logging level

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>

* Fix bug with comparison to NAN

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
2020-10-27 07:24:26 +13:00
Tim Savage
d97a9bf8e8 Added tmp102 temperature sensor support (#929)
* Added tmp102 temperature sensor support

* Added sensor to test3.yaml

* Moved docstring to component root

* Tweak formatting from clang-format script

* Removed extra newline at the end of the file to satisfy pylint

* Update schema to match that of other single-value sensors

In ESPHome, sensors that only expose one value do not put the sensor under another key.

* Add missing import

* Fix test after structural change to component

* removed unused setting

* Update esphome/components/tmp102/tmp102.cpp

Co-authored-by: Otto Winter <otto@otto-winter.com>
Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2020-10-27 07:00:43 +13:00
Alexander Leisentritt
f034472e2a Add LYWSD02 battery sensor (#1334)
* add battery sensor for lywsd02

* update test
2020-10-27 06:53:17 +13:00
dependabot[bot]
ed328d2df8 Bump colorlog from 4.2.1 to 4.4.0 (#1323)
Bumps [colorlog](https://github.com/borntyping/python-colorlog) from 4.2.1 to 4.4.0.
- [Release notes](https://github.com/borntyping/python-colorlog/releases)
- [Commits](https://github.com/borntyping/python-colorlog/compare/v4.2.1...v4.4.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-25 13:17:12 -03:00
dependabot[bot]
1520dc8755 Bump pytest from 6.0.2 to 6.1.1 (#1320)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.2 to 6.1.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.2...6.1.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-25 13:13:51 -03:00
dependabot[bot]
bf601c3126 Bump flake8 from 3.8.3 to 3.8.4 (#1319)
Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.8.3 to 3.8.4.
- [Release notes](https://gitlab.com/pycqa/flake8/tags)
- [Commits](https://gitlab.com/pycqa/flake8/compare/3.8.3...3.8.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-25 13:12:55 -03:00
Guillermo Ruffino
ab48e4a466 Merge pull request #1333 from esphome/bump-1.15.3
1.15.3
2020-10-23 00:16:18 -03:00
Guillermo Ruffino
8ef0f5b047 Lint 2020-10-23 00:06:05 -03:00
Guillermo Ruffino
2c14d134be Bump version to v1.15.3 2020-10-22 23:54:44 -03:00
ikatkov
9cd21bb5a0 AQICalculator is off by 1 (#1331)
Co-authored-by: Igor Katkov <ikatkov@atlassian.com>
2020-10-22 23:54:40 -03:00
thejonesyboy
bd061ac2ee fix: Incorrect time delay conversion breaks remote_transmitter_esp8266.cpp (#1322)
* Incorrect time delay conversion breaks remote_transmitter_esp8266.cpp

I'm unsure why the conversion from microseconds into whole millseconds and remaining microseconds is done using a value of 16383, rather than 1000. This breaks the "on", "off" times, as well as the repeat wait_time if the period is more than 16383 microseconds.

I have confirmed behaviour with an oscilloscope. See https://community.home-assistant.io/t/infrared-remote-transmitter-not-working/232825

* Update esphome/core/helpers.cpp

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
2020-10-22 23:54:39 -03:00
Andrej Komelj
dd3e821857 fix mqtt config check in OnlyWith configuration helper (#1304)
* fix config check in OnlyWith configuration helper

OnlyWith configuration helper check now verifies whether a component
is configured in any of the packages not only in raw configuration

* fix C0301(line-too-long) pylint in imports

* fix flake8 (E127) over-indented line
2020-10-22 23:54:25 -03:00
Guillermo Ruffino
b38b7019ea Fix scheduler with too many cancelled timers (#1309)
* Fix scheduler with too many cancelled timers

* lint

* use variable name
2020-10-22 23:46:38 -03:00
Marvin Gaube
2c71ee7853 Fix RGBW color-interlock control (#1325) 2020-10-22 23:46:37 -03:00
Alexander Leisentritt
540c62061d Fix Xiaomi merged packet parsing (#1293)
* Fix Xiaomi merged packet parsing

solves #1500

* renamed variables and updated payload and value checking

* renamed function and parameter

* add function to header

* changed log message
2020-10-22 23:46:35 -03:00
MartinWelsch
221ef07c8b Fix Light Trigger (#1308)
* make LightTransitionTransformer publish at end

* adjust on trigger + cleanup

* add target_state_reached_callback_

* fix format

* revert publish_at_end change

* fix bug for rapid on/off switching + remove debug logging

* formatting

* call state reached callback when no transition

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
2020-10-22 23:46:34 -03:00
Samuel Sieb
29fc7ea154 Fix max7219digit chip_rotation: 180 (#1321)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2020-10-22 23:46:32 -03:00
ikatkov
7b157aeff1 AQICalculator is off by 1 (#1331)
Co-authored-by: Igor Katkov <ikatkov@atlassian.com>
2020-10-22 23:33:12 -03:00
thejonesyboy
e50644edee fix: Incorrect time delay conversion breaks remote_transmitter_esp8266.cpp (#1322)
* Incorrect time delay conversion breaks remote_transmitter_esp8266.cpp

I'm unsure why the conversion from microseconds into whole millseconds and remaining microseconds is done using a value of 16383, rather than 1000. This breaks the "on", "off" times, as well as the repeat wait_time if the period is more than 16383 microseconds.

I have confirmed behaviour with an oscilloscope. See https://community.home-assistant.io/t/infrared-remote-transmitter-not-working/232825

* Update esphome/core/helpers.cpp

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
2020-10-22 23:25:33 -03:00
Andrej Komelj
5f619e6f01 fix mqtt config check in OnlyWith configuration helper (#1304)
* fix config check in OnlyWith configuration helper

OnlyWith configuration helper check now verifies whether a component
is configured in any of the packages not only in raw configuration

* fix C0301(line-too-long) pylint in imports

* fix flake8 (E127) over-indented line
2020-10-15 10:14:07 -03:00
Guillermo Ruffino
b266fb37a3 Fix scheduler with too many cancelled timers (#1309)
* Fix scheduler with too many cancelled timers

* lint

* use variable name
2020-10-15 10:12:31 -03:00
Marvin Gaube
c9caf44c2e Fix RGBW color-interlock control (#1325) 2020-10-15 09:48:12 -03:00
Alexander Leisentritt
0c87a9ad2c Fix Xiaomi merged packet parsing (#1293)
* Fix Xiaomi merged packet parsing

solves #1500

* renamed variables and updated payload and value checking

* renamed function and parameter

* add function to header

* changed log message
2020-10-12 23:06:09 -03:00
Guillermo Ruffino
c680b437f5 handle windows filenames (#1307) 2020-10-12 22:55:18 -03:00
MartinWelsch
4988349677 Fix Light Trigger (#1308)
* make LightTransitionTransformer publish at end

* adjust on trigger + cleanup

* add target_state_reached_callback_

* fix format

* revert publish_at_end change

* fix bug for rapid on/off switching + remove debug logging

* formatting

* call state reached callback when no transition

Co-authored-by: Guillermo Ruffino <glm.net@gmail.com>
2020-10-10 22:50:53 -03:00
Samuel Sieb
e35d56defe Fix max7219digit chip_rotation: 180 (#1321)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2020-10-06 10:15:40 +13:00
Ash McKenzie
5c86f332b2 Add new time.has_time condition (#1255) 2020-10-04 17:22:28 +02:00
dubit0
002861f13b Float output: Fix min_power and max_power adjusting when output is inverted (#1250)
This patch fixes faulty behaviour when both, invert and min_power/max_power
are set for a float output (e.g. PWM). The current code scales the output
level to the range [min_power, max_power] and subsequently inverts the value.
This leads to values that are outside the range [min_power, max_power].

This patch fixes the problem by inverting the requested level first and then
scaling it to the interval [min_power, max_power].

Co-authored-by: Thomas Niederprüm <niederp@physik.uni-kl.de>
2020-10-01 19:55:42 -03:00
James Gao
dbec3d7c50 Typo in the pm2.5 grid (#1311)
The incorrect pm2.5 grid results in incorrect AQI values in the 51-100 range.
2020-10-01 19:47:29 -03:00
Ivo-tje
89cde158d6 Table row wasn't closed (#1310)
Co-authored-by: Ivo <ivo-gitlab@schooneman.net>
2020-10-02 07:00:00 +13:00
buxtronix
d7b76aadb2 Support Daikin horizontal swing (#1247)
Co-authored-by: Ben Buxton <bb@cactii.net>
2020-10-01 11:24:55 -03:00
Jesse Hills
e09fefd389 Dont fast fail testing so results are not hidden in matrix builds (#1286) 2020-09-30 06:50:06 +13:00
dependabot[bot]
febc485da6 Bump pytest-cov from 2.10.0 to 2.10.1 (#1253)
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.10.0 to 2.10.1.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.10.0...v2.10.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-27 20:31:46 -03:00
dependabot[bot]
2ae709c2ba Bump paho-mqtt from 1.5.0 to 1.5.1 (#1297)
Bumps [paho-mqtt](https://github.com/eclipse/paho.mqtt.python) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/eclipse/paho.mqtt.python/releases)
- [Changelog](https://github.com/eclipse/paho.mqtt.python/blob/master/ChangeLog.txt)
- [Commits](https://github.com/eclipse/paho.mqtt.python/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-27 20:31:21 -03:00
rspaargaren
0ccfdd4711 Enable reverse display of the Max7219 digit (#1234)
* add reverse option

* Update max7219digit.cpp

adding space for formatting

* Update esphome/components/max7219digit/display.py

Copy past error...

Co-authored-by: Otto Winter <otto@otto-winter.com>

Co-authored-by: Otto Winter <otto@otto-winter.com>
2020-09-28 06:17:28 +13:00
Florian Gareis
0e59243b83 Replace CENTER_LEFT with TOP_LEFT to match other printf function (#1295) 2020-09-26 22:02:13 +12:00
Kevin Pelzel
01bbd04a5a Add Fan and Swing Support to fujitsu-general Component (#1287)
* Added fan and swing support to fujitsu-general

* fixed formatting
2020-09-24 00:07:51 -03:00
Guillermo Ruffino
a3b2d384f5 Merge pull request #1292 from esphome/bump-1.15.2
1.15.2
2020-09-20 11:37:33 -03:00
Guillermo Ruffino
50238f8d72 Bump version to v1.15.2 2020-09-20 11:30:30 -03:00
Luke Fitzgerald
704470d606 fix(remote_receiver): Add missing pin setup for ESP32 (#1252) 2020-09-20 11:30:25 -03:00
Jesse Hills
f7e6195466 Readds the battery level for xiaomi_hhccjcy01 (#1288) 2020-09-20 11:30:24 -03:00
Jesse Hills
a0bb7c3ed0 Adds new homeassistant.tag_scanned action (#1281) 2020-09-20 11:30:22 -03:00
Luke Fitzgerald
e3a6c9a6cf fix(remote_receiver): Add missing pin setup for ESP32 (#1252) 2020-09-19 23:40:33 -03:00
Jesse Hills
99598d87a9 Readds the battery level for xiaomi_hhccjcy01 (#1288) 2020-09-19 23:37:34 -03:00
EmbeddedDevver
b5df50893b Update max31855.cpp (#1273)
line 47: mem 

It's valid to have mem value of zero (0) when the temperature of the IC and the k-probe equals exactly zero degrees.
2020-09-16 12:41:29 +02:00
dependabot[bot]
f46b3d15cd Bump platformio from 4.3.4 to 5.0.1 (#1275)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Otto Winter <otto@otto-winter.com>
2020-09-16 12:38:33 +02:00
dependabot[bot]
041b4ec66e Bump pytest from 6.0.1 to 6.0.2 (#1280)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.1...6.0.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-16 12:32:52 +02:00
Jesse Hills
703e9673c2 Adds new homeassistant.tag_scanned action (#1281) 2020-09-16 12:29:20 +02:00
dependabot[bot]
e7bd93b4b0 Bump pylint from 2.5.3 to 2.6.0 (#1262)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Otto Winter <otto@otto-winter.com>
2020-09-16 12:12:40 +02:00
dependabot[bot]
a401c71d3e Bump protobuf from 3.12.4 to 3.13.0 (#1254)
Bumps [protobuf](https://github.com/protocolbuffers/protobuf) from 3.12.4 to 3.13.0.
- [Release notes](https://github.com/protocolbuffers/protobuf/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf/blob/master/generate_changelog.py)
- [Commits](https://github.com/protocolbuffers/protobuf/compare/v3.12.4...v3.13.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-15 17:18:18 +02:00
dependabot[bot]
5bae233334 Bump pytest-mock from 3.2.0 to 3.3.1 (#1263)
Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.2.0 to 3.3.1.
- [Release notes](https://github.com/pytest-dev/pytest-mock/releases)
- [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.2.0...v3.3.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-09-15 17:16:32 +02:00
Guillermo Ruffino
c4edd3047f Merge pull request #1278 from esphome/bump-1.15.1
1.15.1
2020-09-14 22:03:13 -03:00
Guillermo Ruffino
c50da1593a Bump version to v1.15.1 2020-09-14 21:39:08 -03:00
Jesse Hills
1d06426281 Adds support for Tuya Climate temperature multiplier (#1276)
* Adds support for temperature multiplier

* Add new multiplier to test file

* Remove import

* Fixes
2020-09-14 21:39:04 -03:00
akoivist
9c5b693dd5 Fix for Ruuvi voltage parsing of RAWv2 format (#1267)
Power_info should be 2 bytes, so changed uint8 to uint16. With uint8 voltage is always reported to be near 1.6V.
2020-09-14 21:39:03 -03:00
Guillermo Ruffino
5fecc70db1 fix sntp timezone (#1266) 2020-09-14 21:39:01 -03:00
Jesse Hills
ff24023b39 Adds support for Tuya Climate temperature multiplier (#1276)
* Adds support for temperature multiplier

* Add new multiplier to test file

* Remove import

* Fixes
2020-09-14 19:33:37 -03:00
Guillermo Ruffino
1a04e2d1b8 Merge pull request #1277 from esphome/bump-1.15.0
1.15.0
2020-09-13 16:23:51 -03:00
Guillermo Ruffino
52c4dd0e35 Bump version to v1.15.0 2020-09-13 14:18:32 -03:00
Guillermo Ruffino
ff90f6a440 Merge branch 'beta' into bump-1.15.0 2020-09-13 14:18:19 -03:00
akoivist
e24d5c172f Fix for Ruuvi voltage parsing of RAWv2 format (#1267)
Power_info should be 2 bytes, so changed uint8 to uint16. With uint8 voltage is always reported to be near 1.6V.
2020-09-01 19:17:15 -03:00
Guillermo Ruffino
0918f452a0 fix sntp timezone (#1266) 2020-09-01 19:15:26 -03:00
Guillermo Ruffino
839fe49e61 Merge pull request #1259 from esphome/bump-1.15.0b4
1.15.0b4
2020-08-23 22:08:10 -03:00
Guillermo Ruffino
ff050d634a Bump version to v1.15.0b4 2020-08-23 21:53:50 -03:00
Keith Burzinski
228670df78 Fix SSD1306 post-setup brightness control (#1090)
* Fix post-setup brightness control

* Add turn_on() and turn_off() methods

* Added is_on() method

* Set brightness later in setup()

* Use clamp() for brightness validation
2020-08-23 21:53:46 -03:00
Guillermo Ruffino
cfe4638665 fixes deg symbol not shown (#1248) 2020-08-23 21:53:45 -03:00
Guillermo Ruffino
b7352b1345 Image bit dephts (#1241) 2020-08-23 21:53:43 -03:00
Otto Winter
32ae8fc2d0 Bump docker base image to 2.6.0 (#1245) 2020-08-23 21:53:41 -03:00
Guillermo Ruffino
86df4c1d8d make powered on assume public (#1240) 2020-08-23 21:53:40 -03:00
Jesse Hills
dc4a88029c Script mode fix (#1238) 2020-08-23 21:53:38 -03:00
Otto Winter
5da9b2ede7 Fix tuya.cpp compile warning (#1232) 2020-08-23 21:53:37 -03:00
Otto Winter
29cfcfaf0f Fix ESP8266 core has a broken settimeofday implementation (#1231) 2020-08-23 21:53:36 -03:00
Otto Winter
61bfd347ea Bump ESPAsyncTCP from 1.2.2 to 1.2.3 (#1227) 2020-08-23 21:53:34 -03:00
Otto Winter
b7436c0b22 Bump ESP8266 Arduino framework from 2.7.2 to 2.7.3 (#1229) 2020-08-23 21:53:33 -03:00
Otto Winter
8a45dfac5c Fix release.yml invalid bash syntax (#1226) 2020-08-23 21:53:32 -03:00
Keith Burzinski
69f5d8cd0f Fix SSD1306 post-setup brightness control (#1090)
* Fix post-setup brightness control

* Add turn_on() and turn_off() methods

* Added is_on() method

* Set brightness later in setup()

* Use clamp() for brightness validation
2020-08-23 20:36:11 -03:00
Guillermo Ruffino
9a57e8fcb0 fixes deg symbol not shown (#1248) 2020-08-13 23:21:19 -03:00
Guillermo Ruffino
a9d75ca4f4 Image bit dephts (#1241) 2020-08-11 15:28:30 +02:00
Otto Winter
ccb6fc3010 Bump docker base image to 2.6.0 (#1245) 2020-08-08 18:42:21 +02:00
dependabot[bot]
4e9a05fe11 Bump pytest from 6.0.0 to 6.0.1 (#1236)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.0.0 to 6.0.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.0.0...6.0.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-08-08 18:33:30 +02:00
Ian Leeder
8a294e4134 Clean up ALLOWED_CHARS (#1235) 2020-08-06 17:29:45 +02:00
Guillermo Ruffino
aad9a539c1 make powered on assume public (#1240) 2020-08-06 17:13:19 +02:00
Jesse Hills
fd6ac529fb Script mode fix (#1238) 2020-08-06 17:08:48 +02:00
Otto Winter
009cea1abf Fix tuya.cpp compile warning (#1232) 2020-07-30 17:26:40 +02:00
Otto Winter
4c3c14ec32 Fix ESP8266 core has a broken settimeofday implementation (#1231) 2020-07-30 11:41:06 +02:00
Otto Winter
636c9db1e3 Bump ESPAsyncTCP from 1.2.2 to 1.2.3 (#1227) 2020-07-30 11:38:57 +02:00
dependabot[bot]
71f625bbd3 Bump protobuf from 3.12.2 to 3.12.4 (#1230)
Bumps [protobuf](https://github.com/protocolbuffers/protobuf) from 3.12.2 to 3.12.4.
- [Release notes](https://github.com/protocolbuffers/protobuf/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf/blob/master/generate_changelog.py)
- [Commits](https://github.com/protocolbuffers/protobuf/compare/v3.12.2...v3.12.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-30 10:31:53 +02:00
Ian Leeder
aea2e9a6bb Add hyphen to supported name characters (#1223)
Co-authored-by: Otto Winter <otto@otto-winter.com>
2020-07-30 00:02:34 +02:00
Otto Winter
3f6f3c14c4 Bump ESP8266 Arduino framework from 2.7.2 to 2.7.3 (#1229) 2020-07-29 23:29:38 +02:00
Otto Winter
b1d77b7c03 Fix release.yml invalid bash syntax (#1226) 2020-07-29 20:45:47 +02:00
Otto Winter
49233e4734 Merge pull request #1225 from esphome/bump-1.15.0b3
1.15.0b3
2020-07-29 20:19:06 +02:00
Otto Winter
e2b5ecb78b Bump version to v1.15.0b3 2020-07-29 20:05:22 +02:00
Otto Winter
351ce67eae Bump base image to 2.4.1 (#1224) 2020-07-29 20:05:22 +02:00
dr-oblivium
44af5e439c wpa2 enterprise fixes: also copy eap parameters, don't require psk password to be set (#1215) 2020-07-29 20:05:22 +02:00
Otto Winter
dbc0d500d8 Bump ESPAsyncWebServer-esphome to v1.2.7 (#1221) 2020-07-29 20:05:21 +02:00
Emil Hesslow
86736aa480 Stop infinite loop in light on_turn_on (#1219)
Co-authored-by: Otto Winter <otto@otto-winter.com>
2020-07-29 20:05:21 +02:00
Otto Winter
57eb05c0e3 Add job to update HassIO addon repo (#1218) 2020-07-29 20:05:21 +02:00
Guillermo Ruffino
f6fe6e6bff renamed icon molecule co2 (#1217)
* renamed icon molecule co2

* sort of course
2020-07-29 20:05:20 +02:00
Otto Winter
18560f9430 Fix sdist missing requirements.txt (#1214)
Fixes https://github.com/esphome/issues/issues/1378
2020-07-29 20:05:20 +02:00
Otto Winter
cb0ba647ed Bump base image to 2.4.1 (#1224) 2020-07-29 20:04:14 +02:00
Otto Winter
f9fceb7ffc Fix ci-custom.py const.py ordered check and improve code (#1222) 2020-07-29 18:19:48 +02:00
dr-oblivium
2697c9465b wpa2 enterprise fixes: also copy eap parameters, don't require psk password to be set (#1215) 2020-07-29 18:18:53 +02:00
Otto Winter
8d204655be Bump ESPAsyncWebServer-esphome to v1.2.7 (#1221) 2020-07-29 12:57:43 +02:00
dependabot[bot]
8414a22356 Bump pytest from 5.4.3 to 6.0.0 (#1220)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.4.3 to 6.0.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/5.4.3...6.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-29 09:15:10 +02:00
Emil Hesslow
36e4a8b444 Stop infinite loop in light on_turn_on (#1219)
Co-authored-by: Otto Winter <otto@otto-winter.com>
2020-07-29 09:13:51 +02:00
Otto Winter
949c71dc97 Add job to update HassIO addon repo (#1218) 2020-07-28 23:25:55 +02:00
Guillermo Ruffino
a6f6b8da7f renamed icon molecule co2 (#1217)
* renamed icon molecule co2

* sort of course
2020-07-28 15:17:24 -03:00
Otto Winter
a9f123e864 Remove overview job from CI (#1216) 2020-07-28 19:07:42 +02:00
Otto Winter
a64a505817 Fix sdist missing requirements.txt (#1214)
Fixes https://github.com/esphome/issues/issues/1378
2020-07-28 14:29:01 +02:00
Otto Winter
fe6621357e Downgrade FastLED to 3.3.2 (#1212)
Fixes https://github.com/esphome/issues/issues/1375
2020-07-28 12:10:55 +02:00
Otto Winter
4a0067a2c5 Fix prometheus has wrong setup priority (#1211)
Fixes https://github.com/esphome/issues/issues/1377
2020-07-28 12:01:38 +02:00
Gediminas Šaltenis
b270ff335d Fix AS3935 sensor configuration issues (#1210)
* Fix AS3935 coniguration

* Increase verbosity
2020-07-28 10:34:42 +02:00
Otto Winter
7d2fcf59fd Fix base config should override packages config (#1209) 2020-07-27 18:23:00 +02:00
Otto Winter
d26c43103d ESP8266 change recommended framework version to 2.7.2 (#1208) 2020-07-27 18:22:47 +02:00
Otto Winter
389889ad70 Mitigate CVE-2020-12638 WiFi WPA Downgrade (#1207)
Co-authored-by: Lukas Bachschwell <lukas@lbsfilm.at>
2020-07-27 18:22:38 +02:00
Otto Winter
8aa73bba10 Fix publish release script 2020-07-27 12:28:11 +02:00
Otto Winter
52639a0a7c Cleanup web server prometheus integration (#1192) 2020-07-27 12:07:05 +02:00
Guillermo Ruffino
a1e10f384e fix dashboard select drop down (#1205) 2020-07-27 11:43:51 +02:00
dependabot[bot]
27d4b3b8ad Update cryptography requirement from <3,>=2.0.0 to >=2.0.0,<4 (#1206)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Otto Winter <otto@otto-winter.com>
2020-07-27 11:43:10 +02:00
Otto Winter
b9d55fd1ed Also run CI checks when merging against beta/master 2020-07-26 22:42:59 +02:00
Otto Winter
4c55b9c58c Bump version to v1.16.0-dev 2020-07-26 22:12:58 +02:00
Guillermo Ruffino
51ab0f0b78 Bump version to v1.14.5 2020-06-23 22:39:24 -03:00
Otto Winter
bf0cce4ad8 Fix ESP32 interrupt enable/disable switched
Needs to be manually cherry-picked
2020-06-23 22:36:00 -03:00
Otto Winter
60e6366521 Bump version to v1.14.4 2020-06-05 12:56:23 +02:00
Otto Winter
072b2c445c Add ESP8266 core v2.6.2 (#905)
* Add ESP8266 core v2.6.2

* Upstream ESP8266 Wifi fixes

* Replace disable_interrupt with InterruptLock C++ class

* Update code to use InterruptLock

* Lint

* Update dht.cpp

* Improve InterruptLock docs, mark as ICACHE_RAM_ATTR

* Fixes
2020-06-05 12:56:10 +02:00
Otto Winter
219fe41831 Update ESP32 BLE ADV parse to match BLE spec (#904)
* Update ESP32 BLE ADV parse to match BLE spec

* Update xiaomi

* Update ruuvi

* Format

* Update esp32_ble_tracker.cpp

* Fix log

* Format

* Update xiaomi_ble.cpp
2020-06-05 12:55:24 +02:00
Otto Winter
dcc8bb83af Ignore ESP32 Camera unknown framesizes (#901)
Fixes https://github.com/esphome/issues/issues/866
2020-06-05 12:52:05 +02:00
Otto Winter
a8e3521f3c web_server call setup_controller (#899) 2020-06-05 12:52:05 +02:00
Otto Winter
706dc6d116 Fix MQTT logs Int or String expected Python 3 (#898)
Fixes https://github.com/esphome/issues/issues/850
2020-06-05 12:52:04 +02:00
Guillermo Ruffino
84accb6df6 fix climate_ir on receive optional (#897)
* fix climate on receive optional

* add climate tests
2020-06-05 12:52:04 +02:00
warpzone
8421570b18 fix the problem of missing part of advertising packet when activ… (#868)
* fix the problem of missing part of advertising packet when active scan is enabled.

* fix for ci-suggest-changes
2020-06-05 12:52:04 +02:00
Otto Winter
d355543ac9 Merge branch '1.14.4' 2020-06-05 12:42:56 +02:00
Otto Winter
3a597c5aa6 Fix gitignore intellij idea 2020-06-05 12:38:05 +02:00
Otto Winter
c7dddaded4 Upgrade docker base image to 2.1.1 2020-06-05 12:28:37 +02:00
Otto Winter
aae4b2ea5d Upgrade docker base image to 2.1.0 2020-06-05 12:27:26 +02:00
Otto Winter
310e2a0b20 Fix build 2020-06-05 12:25:29 +02:00
Niklas Wagner
0b04d143ac Upgrade dependencies 2020-06-05 12:00:20 +02:00
Otto Winter
53c231a7eb Revert "Atm90e32 pf fix (#841)"
This reverts commit 7842a55c81.
2019-11-17 23:37:00 +01:00
Otto Winter
d44ce82aa1 Bump version to v1.14.3 2019-11-17 23:34:04 +01:00
Otto Winter
a055de48e4 Change ESP8266 default wifi output power (#862)
See also https://github.com/esphome/issues/issues/455
2019-11-17 23:34:01 +01:00
Otto Winter
37b8d665fe Revert ESP32 BLE Tracker defaults (#863)
Fixes https://github.com/esphome/issues/issues/824
Fixes https://github.com/esphome/issues/issues/851
2019-11-17 23:34:01 +01:00
Otto Winter
dd7c8dabb1 Fix MQTT python 3 stringify IPAddress Type (#864)
Fixes https://github.com/esphome/issues/issues/850
2019-11-17 23:34:01 +01:00
Otto Winter
e41a9875e3 Improve WiFi disconnect messages (#857)
* Improve WiFi disconnect messages

* Fix

* Update wifi_component_esp32.cpp
2019-11-17 23:34:01 +01:00
Brandon Davidson
c5c42c4338 Tuya: Fix init sequence and handle wifi test command (#820)
* Handle WiFi test command

Also rename commands to match Tuya protocol docs

* Fix init sequence and product info check

* Fix clang-format suggestions

* Additional changes based on code review

* Fix temp command buffer scope

* Let the interval timer fire the first heatbeat

* Fix init steps; add logging

* Lint

* Remove setup_priority override

* Add delay to dump_config

* Refactor dump sequence

* Fix verbose logging

* Fix lints

* Don't bother suppressing duplicate config dumps

* nolint


Co-authored-by: Otto Winter <otto@otto-winter.com>
2019-11-17 23:34:00 +01:00
Brandon Davidson
531428b8b0 Fix logger uart conflict check (#858)
* Fix logger uart conflict check

* Fix class for check func

* Fix syntax

Hope lint is OK with moving the end of the conditional outside the #IFDEF

* Move end of conditional inside ifdef and remove extra whitespace

* Simplify

clang-format did not like the ifdefs and was reformatting in a way that killed clang-tidy.

Simple solution is to use logger's hw_serial as source of truth

Also simplifies the code - uart doesn't need to know what the logger uart settings mean
2019-11-17 23:34:00 +01:00
Otto Winter
ea8068e001 Switch to 115200 baud upload if 460800 fails (#856)
* Switch to 115200 baud upload if 460800 fails

* Update __main__.py
2019-11-17 23:34:00 +01:00
Mark
7842a55c81 Atm90e32 pf fix (#841)
* correct set_pf_sensor to set_power_factor_senor

* remove junk files added in error

* correct sensors.yaml reference to set_reactive_power

* Fixes
2019-11-17 23:33:56 +01:00
Samuel Sieb
51d39862b1 add position reporting to the template cover (#821)
* add position reporting to the template cover

* remove duplicate import

* use config flag instead


Co-authored-by: Samuel Sieb <samuel@sieb.net>
2019-11-17 23:33:21 +01:00
Otto Winter
bfea6ca79b Mark python 3.5 support deprecated (#849)
* Mark python 3.5 unsupported

Fixes https://github.com/esphome/issues/issues/831

* Update .travis.yml

* Update typing dep
2019-11-17 23:33:20 +01:00
Otto Winter
6297395018 Fix PZEM004T v2 (#846)
Fixes https://github.com/esphome/issues/issues/817
2019-11-17 23:33:20 +01:00
Otto Winter
a5b49dbfa6 Adjust some units (#852)
* Adjust some units

Fixes https://github.com/esphome/issues/issues/843

* Lint
2019-11-17 23:33:12 +01:00
Otto Winter
7c0d777173 Check DHT sensor exists before publishing (#850)
Fixes https://github.com/esphome/issues/issues/841
2019-11-17 23:31:36 +01:00
Otto Winter
74878276fc Web server CORS headers (#840)
* Add CORS header to web server

* Refactor

* Cleanup

See also https://github.com/esphome/issues/issues/806
2019-11-17 23:31:35 +01:00
Otto Winter
226e3b1dad Fix sensor force_update native API (#847)
Fixes https://github.com/esphome/issues/issues/842
2019-11-17 23:31:35 +01:00
Otto Winter
7752794fc5 Fix neopixelbus missing method pins (#848)
Fixes https://github.com/esphome/issues/issues/839
2019-11-17 23:31:35 +01:00
Otto Winter
b3094d6a53 Add missing state attribute (#851)
* Add api missing_state attribute

Fixes https://github.com/esphome/issues/issues/828

Adds a new property for missing state, so that HA can now when a sensor does not have a state yet.

* Update api.proto
2019-11-17 23:31:35 +01:00
Otto Winter
e3640e710f Add wifi output_power setting (#853)
* Add wifi output_power setting

See also:
 - https://github.com/esphome/feature-requests/issues/471#issuecomment-552350467
 - https://github.com/esp8266/Arduino/issues/6366
 - https://github.com/esp8266/Arduino/issues/6471
 - 849f8cf920/code/espurna/config/general.h (L593-L599)
 - https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/network/esp_wifi.html#_CPPv425esp_wifi_set_max_tx_power6int8_t

* Lint
2019-11-17 23:31:35 +01:00
Guillermo Ruffino
2ef64b55c5 fix missing checks of is_playing condition (#844) 2019-11-17 23:31:34 +01:00
Otto Winter
7f6672bb37 Fix calculations for negative sun declination (#839)
Fixes https://github.com/esphome/issues/issues/793

Also adds a clampd function that operates with doubles, not floats
2019-11-17 23:31:34 +01:00
Otto Winter
68a3b31628 Update variable in scheduler (#838)
Fixes https://github.com/esphome/issues/issues/826
2019-11-17 23:31:34 +01:00
Otto Winter
1b35855e68 Update platformio libraries (#837)
* Update platformio libraries

* Lint
2019-11-17 23:31:34 +01:00
Otto Winter
1e1837000d Fix homeassistant.service schema lambda (#833)
* Fix homeassistant.service schema lambda

Fixes https://github.com/esphome/issues/issues/820

* Improve

* Fix
2019-11-17 23:31:34 +01:00
Otto Winter
e2d5257632 Fix ESP32 rotary encoder (#834)
* Fix ESP32 rotary encoder

Fixes https://github.com/esphome/issues/issues/672

* Update rotary_encoder.cpp

* Lint
2019-11-17 23:31:34 +01:00
Otto Winter
387c75793b WiFi AP apply manual ip settings (#836) 2019-11-17 23:31:33 +01:00
Otto Winter
4f3a74d08a ESP8266 remove default opmode check (#835) 2019-11-17 23:31:33 +01:00
Otto Winter
fdbc59a159 Bump version to v1.14.2 2019-11-03 00:20:31 +01:00
Otto Winter
0db37bb55c Fix weird ESP8266 wifi crashes (#831)
* Try fix ESP8266 weird crashes

* Only call disconnect if STA is active
2019-11-03 00:20:25 +01:00
Otto Winter
2ff2750628 Fix stack trace decode for latest platformio (#830) 2019-11-02 21:19:36 +01:00
Otto Winter
eae5c17b87 Bump version to v1.14.1 2019-11-02 21:00:05 +01:00
Otto Winter
a59cde91ad Add servo missing restore option to codegen (#829)
See also https://github.com/esphome/issues/issues/609
2019-11-02 20:59:56 +01:00
Otto Winter
1f243ae37e Remove PCF8574 input_pullup mode and cleanup (#828)
Fixes https://github.com/esphome/issues/issues/755
Closes https://github.com/esphome/esphome/pull/822
Fixes https://github.com/esphome/issues/issues/667
Closes https://github.com/esphome/esphome/pull/808

Co-Authored-By: Amish Vishwakarma <amishv@users.noreply.github.com>
Co-Authored-By: S-Przybylski <s-przybylski@users.noreply.github.com>
2019-11-02 20:59:56 +01:00
Otto Winter
603f82977e Fix update-all input in dashboard (#826)
Fixes https://github.com/esphome/issues/issues/798
2019-11-02 20:59:56 +01:00
Otto Winter
2d70422a6f Move native API enums to new namespace (#825)
Fixes https://github.com/esphome/issues/issues/801
2019-11-02 20:59:55 +01:00
Otto Winter
e2c8b21195 Fix wizard mkdir (#824)
* Fix CLI wizard mkdir_p with empty path

Fixes https://github.com/esphome/issues/issues/796

* Cleanup

* Lint
2019-11-02 20:59:55 +01:00
Alexander Leisentritt
7adaeacd0b refactored xiaomi ble data parsing (#823) 2019-11-02 20:59:55 +01:00
Otto Winter
3aaa92fdff Bump version to v1.14.0 2019-11-01 18:27:24 +01:00
Otto Winter
5efd076c08 Merge branch 'beta' 2019-11-01 18:26:19 +01:00
Otto Winter
1ca241615d Bump version to v1.13.6 2019-06-14 12:55:23 +02:00
Otto Winter
b8aa84002a Re-add CustomMQTTDevice class (#640)
* Re-add CustomMQTTDevice class

Fixes https://github.com/esphome/issues/issues/427

* Fix
2019-06-14 12:55:20 +02:00
Otto Winter
10cc0b1d5b Fix remote_receiver raw binary sensor (#639)
* Fix remote_receiver raw binary sensor

Fixes https://github.com/esphome/issues/issues/439

* Lint
2019-06-14 12:55:19 +02:00
Otto Winter
11d9c203c1 Fix version.h file (#630)
* Fix version.h file

* Lint
2019-06-14 12:55:19 +02:00
Otto Winter
c9ab454c3c Fix globals.set (#635)
* Fix globals.set

* Update __init__.py
2019-06-14 12:55:19 +02:00
Otto Winter
4a55692885 Fix russia timezone detection (#637)
Fixes https://github.com/esphome/issues/issues/378#issuecomment-500219634
2019-06-14 12:55:19 +02:00
Otto Winter
88c129e705 Fix ESP32 RCSwitch Dump Stack Smash Protection (#636)
Fixes https://github.com/esphome/issues/issues/366
2019-06-14 12:55:19 +02:00
Otto Winter
80b48f01fb Fix esp8266_restore_from_flash (#638)
Fixes https://github.com/esphome/issues/issues/424
2019-06-14 12:36:30 +02:00
Otto Winter
642bc91a76 Update esp32_ble_tracker.cpp 2019-06-08 17:06:29 +02:00
Otto Winter
d69926ee56 Bump version to v1.13.5 2019-06-08 16:49:04 +02:00
Otto Winter
4758403d44 Work around ESP32 core WiFi Bug (#627)
* Work around ESP32 WiFi Bug

* Lint
2019-06-08 16:49:00 +02:00
Otto Winter
4b0ec5c28a Work around ESP32 BLE issue (#626) 2019-06-08 16:49:00 +02:00
Otto Winter
4b2a9e5e49 Fix status binary sensor for MQTT (#628)
Fixes https://github.com/esphome/issues/issues/417
2019-06-08 16:48:59 +02:00
Otto Winter
1449c51d49 Update base image to 1.8.3 (#625) 2019-06-08 16:48:59 +02:00
Otto Winter
a451705e0b Fix sun default elevation (#620) 2019-06-08 16:48:58 +02:00
Otto Winter
2e6db39173 Fix integration sensor, add test (#619)
* Fix integration sensor, add test

* Fix

* Fix
2019-06-08 16:48:58 +02:00
Otto Winter
373f75253c Update docker base image to 1.8.0 (#618) 2019-06-08 16:48:58 +02:00
Otto Winter
724842084e Make ForCondition a component (#616)
Fixes https://github.com/esphome/issues/issues/396
2019-06-08 16:48:57 +02:00
Otto Winter
8f3635b167 Fix remote_receiver always shows sony (#617)
Fixes https://github.com/esphome/issues/issues/383#issuecomment-498370572
2019-06-08 16:48:57 +02:00
Otto Winter
11605a36f7 Fix Hass.io addon SSL (#613)
Fixes https://github.com/esphome/issues/issues/404
2019-06-08 16:48:56 +02:00
Otto Winter
533f81d625 Template Cover don't auto-set current_operation (#612)
Fixes https://github.com/esphome/issues/issues/408
2019-06-08 16:48:56 +02:00
Otto Winter
aacb9e44e8 DHT22 ignore invalid values (#614)
Fixes https://github.com/esphome/issues/issues/397
2019-06-08 16:48:55 +02:00
Peter Tatrai
c6e3f1bca6 Fix ForCondition time duration check (#610)
According documentation ForCondition should evaluate to true if a nested condition is true for at least the specified time duration and not the less.
2019-06-08 16:48:55 +02:00
Otto Winter
a933d4aeb6 Move ESPHome version define (#607)
* Move ESPHome version define

* Lint
2019-06-08 16:48:55 +02:00
Otto Winter
caa5b20791 Bump version to v1.13.4 2019-06-03 15:24:10 +02:00
Otto Winter
e2ad9ed746 ESP8266 connect fixes (#605)
* ESP8266 Connection Fixes

* Update client.py

* Update mqtt_client.cpp

* Update mqtt_client.cpp

* Fix ping

* Async dump config

* Update base image to 1.7.0

* Update helpers.py

* Updates

* Update Dockerfile.lint
2019-06-03 15:23:57 +02:00
Otto Winter
32c0e7c2ae Fix ADS1115 calculation (#606)
Fixes https://github.com/esphome/issues/issues/393
2019-06-03 15:23:56 +02:00
Otto Winter
6c564c7b7f Fix validation infinite loop with empty platform block (#598)
* Fix validation infinite loop with empty platform block

* Update util.py
2019-06-03 15:23:56 +02:00
Otto Winter
c81e3a3be4 Fix hx711 (#602)
* Fix HX711

* Use signed value

* Update hx711.cpp
2019-06-03 15:23:56 +02:00
Otto Winter
6b1b9ef7ec Fix color wipe effect (#599) 2019-06-03 15:23:56 +02:00
Otto Winter
c26a8b8718 Allow old remote_transmitter repeat schema (#601)
Fixes https://github.com/esphome/issues/issues/389
2019-06-03 15:23:56 +02:00
Otto Winter
4a89a475bd Add better esphomeyaml migration path (#600)
Fixes https://github.com/esphome/issues/issues/387
2019-06-03 15:23:55 +02:00
Otto Winter
8cf15c7f5c Bump version to v1.13.3 2019-06-01 22:02:10 +02:00
Otto Winter
adc76ca1b8 Fix dashboard for Py3 installs (#596)
Fixes https://github.com/esphome/issues/issues/368
2019-06-01 22:02:05 +02:00
Otto Winter
8f8892440c Fix medium fan speed (#595) 2019-06-01 22:02:04 +02:00
Otto Winter
570843150d Fix flicker light effect turning itself off (#594)
Fixes https://github.com/esphome/issues/issues/382
2019-06-01 22:02:04 +02:00
Otto Winter
f3fc9e4142 Fix remote_receiver binary_sensor (#592)
Fixes https://github.com/esphome/issues/issues/369
2019-06-01 22:02:04 +02:00
Otto Winter
075fcb77a8 Fix timezone detection (#586)
* Fix timezone detection

* Update __init__.py
2019-06-01 22:02:04 +02:00
Otto Winter
e5899ff717 Fix scripts circular dependency (#591)
Fixes https://github.com/esphome/issues/issues/370
2019-06-01 22:02:04 +02:00
Otto Winter
2fb3970027 Fix addressable effects (#590) 2019-06-01 22:02:03 +02:00
Marc-Antoine Courteau
1a4efa1b8c List the correct boards when building for ESP32 (#589)
* List the ESP32 boards for ESP32 builds.

* Sort the list of valid boards.
2019-06-01 22:02:03 +02:00
Otto Winter
72f656ffef Bump version to v1.13.2 2019-05-31 16:37:56 +02:00
Otto Winter
b60239d5e5 Fix i2c setup priority (#585)
Fixes https://github.com/esphome/issues/issues/314
2019-05-31 16:37:49 +02:00
Otto Winter
d02e280c3c Fix light partition (#584)
* Fix light partition

Fixes https://github.com/esphome/issues/issues/365

* Lint
2019-05-31 16:37:48 +02:00
Otto Winter
6535b0966e Fix MQTT on_message trigger (#583)
Fixes https://github.com/esphome/issues/issues/363
Fixes https://github.com/esphome/issues/issues/364
2019-05-31 16:37:48 +02:00
Otto Winter
82dbacbee5 Fix travis build (#582) 2019-05-31 16:37:48 +02:00
Otto Winter
2432901974 Fix Rotary Encoder (#580)
Fixes https://github.com/esphome/issues/issues/360
2019-05-31 16:37:48 +02:00
Otto Winter
ebb5d58c14 Fix MQTT client_id changed (#579)
Fixes https://github.com/esphome/issues/issues/323
2019-05-31 16:37:48 +02:00
Otto Winter
605e365405 Fix remote_receiver binary_sensor schema (#578)
Fixes https://github.com/esphome/issues/issues/353#issuecomment-497491863
2019-05-31 16:37:47 +02:00
Otto Winter
5ab995d8ca Bump version to v1.13.1 2019-05-30 22:31:56 +02:00
Otto Winter
4248741b11 Fix waveshare 7.5in model (#576)
* Fix waveshare 7.5in model

Fixes https://github.com/esphome/issues/issues/357

* Fix platformio travis errors
2019-05-30 22:31:54 +02:00
Otto Winter
4b8ecc7634 Dashboard work around Hass.io bug (#575)
* Dashboard work around Hass.io bug

Ref https://github.com/home-assistant/hassio/issues/1103

* Lint
2019-05-30 22:31:53 +02:00
Otto Winter
25d04c759c Fix Sun Trigger (#572)
* Fix Sun Trigger

* Fix cwww lights
2019-05-30 22:31:53 +02:00
Otto Winter
b4ec84030e Fix validation TypeError (#574) 2019-05-30 22:31:53 +02:00
Otto Winter
29e8761373 Fix merge 2019-05-30 14:20:06 +02:00
Otto Winter
a04299c59e Bump version to v1.13.0 2019-05-30 14:15:41 +02:00
Otto Winter
d7bf3c51d9 Merge branch 'beta' 2019-05-30 14:15:28 +02:00
Otto Winter
ac0b095941 Bump version to v1.12.2 2019-03-31 13:13:12 +02:00
Otto Winter
cda9bad233 Upgrade docker base image to 1.4.3 (#499) 2019-03-31 13:13:09 +02:00
Otto Winter
41db8a1264 Fix text sensor MQTT settings (#495)
Fixes https://github.com/esphome/issues/issues/170
2019-03-31 13:13:09 +02:00
Otto Winter
e7e785fd60 Fix dashboard wizard unicode (#494)
* Fix dashboard wizard unicode

Fixes https://github.com/esphome/issues/issues/169

* Fix password md5
2019-03-31 13:13:08 +02:00
Otto Winter
300d3a1f46 Upgrade ESPAsyncTCP to 1.2.0 (#497) 2019-03-31 13:13:08 +02:00
Otto Winter
356554c08d ESP8266 SDK 2.3.0 compat (#490) 2019-03-31 13:13:08 +02:00
Guillermo Ruffino
ced28ad006 Better symlink support under Windows (#487)
* Better symlink support under Windows

* Conditional loading of ctypes wintypes module

* Shortening comment line for pylint

* Adding plint bypass for Python 3
2019-03-31 13:13:08 +02:00
312 changed files with 13617 additions and 1623 deletions

View File

@@ -25,3 +25,4 @@ indent_size = 2
[*.{yaml,yml}]
indent_style = space
indent_size = 2
quote_type = single

View File

@@ -18,6 +18,7 @@ jobs:
name: Build docker containers
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
arch: [amd64, armv7, aarch64]
build_type: ["hassio", "docker"]
@@ -25,7 +26,7 @@ jobs:
- uses: actions/checkout@v2
- name: Set up env variables
run: |
base_version="2.4.0"
base_version="2.6.0"
if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
@@ -37,9 +38,9 @@ jobs:
dockerfile="docker/Dockerfile"
fi
echo "::set-env name=BUILD_FROM::${build_from}"
echo "::set-env name=BUILD_TO::${build_to}"
echo "::set-env name=DOCKERFILE::${dockerfile}"
echo "BUILD_FROM=${build_from}" >> $GITHUB_ENV
echo "BUILD_TO=${build_to}" >> $GITHUB_ENV
echo "DOCKERFILE=${dockerfile}" >> $GITHUB_ENV
- name: Pull for cache
run: |
docker pull "${BUILD_TO}:dev" || true

View File

@@ -11,45 +11,6 @@ on:
pull_request:
jobs:
# A fast overview job that checks only changed files
overview:
runs-on: ubuntu-latest
container: esphome/esphome-lint:latest
steps:
# Also fetch history and dev branch so that we can check which files changed
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Fetch dev branch
run: git fetch origin dev
# Cache the .pio directory with (primarily) library dependencies
- name: Cache .pio lib_deps
uses: actions/cache@v1
with:
path: .pio
key: lint-cpp-pio-${{ hashFiles('platformio.ini') }}
restore-keys: |
lint-cpp-pio-
- name: Set up python environment
run: script/setup
# Set up the pio project so that the cpp checks know how files are compiled
# (build flags, libraries etc)
- name: Set up platformio environment
run: pio init --ide atom
- name: Register problem matchers
run: |
echo "::add-matcher::.github/workflows/matchers/ci-custom.json"
echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
echo "::add-matcher::.github/workflows/matchers/gcc.json"
echo "::add-matcher::.github/workflows/matchers/lint-python.json"
echo "::add-matcher::.github/workflows/matchers/python.json"
- name: Run a quick lint over all changed files
run: script/quicklint
- name: Suggest changes
run: script/ci-suggest-changes
lint-clang-format:
runs-on: ubuntu-latest
# cpp lint job runs with esphome-lint docker image so that clang-format-*
@@ -83,6 +44,7 @@ jobs:
container: esphome/esphome-lint:latest
# Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
strategy:
fail-fast: false
matrix:
split: [1, 2, 3, 4]
steps:
@@ -146,6 +108,7 @@ jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
test:
- test1

View File

@@ -41,6 +41,7 @@ jobs:
container: esphome/esphome-lint:latest
# Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
strategy:
fail-fast: false
matrix:
split: [1, 2, 3, 4]
steps:
@@ -104,6 +105,7 @@ jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
test:
- test1
@@ -187,10 +189,10 @@ jobs:
- name: Set TAG
run: |
TAG="${GITHUB_SHA:0:7}"
echo "::set-env name=TAG::${TAG}"
echo "TAG=${TAG}" >> $GITHUB_ENV
- name: Set up env variables
run: |
base_version="2.4.0"
base_version="2.6.0"
if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
@@ -202,9 +204,9 @@ jobs:
dockerfile="docker/Dockerfile"
fi
echo "::set-env name=BUILD_FROM::${build_from}"
echo "::set-env name=BUILD_TO::${build_to}"
echo "::set-env name=DOCKERFILE::${dockerfile}"
echo "BUILD_FROM=${build_from}" >> $GITHUB_ENV
echo "BUILD_TO=${build_to}" >> $GITHUB_ENV
echo "DOCKERFILE=${dockerfile}" >> $GITHUB_ENV
- name: Pull for cache
run: |
docker pull "${BUILD_TO}:dev" || true
@@ -241,7 +243,7 @@ jobs:
- name: Set TAG
run: |
TAG="${GITHUB_SHA:0:7}"
echo "::set-env name=TAG::${TAG}"
echo "TAG=${TAG}" >> $GITHUB_ENV
- name: Log in to docker hub
env:
DOCKER_USER: ${{ secrets.DOCKER_USER }}

View File

@@ -40,6 +40,7 @@ jobs:
container: esphome/esphome-lint:latest
# Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
strategy:
fail-fast: false
matrix:
split: [1, 2, 3, 4]
steps:
@@ -103,6 +104,7 @@ jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
test:
- test1
@@ -207,10 +209,10 @@ jobs:
- name: Set TAG
run: |
TAG="${GITHUB_REF#refs/tags/v}"
echo "::set-env name=TAG::${TAG}"
echo "TAG=${TAG}" >> $GITHUB_ENV
- name: Set up env variables
run: |
base_version="2.4.0"
base_version="2.6.0"
if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
@@ -222,13 +224,20 @@ jobs:
dockerfile="docker/Dockerfile"
fi
if [[ "${{ github.event.release.prerelease }}" == "true" ]]; then
cache_tag="beta"
else
cache_tag="latest"
fi
# Set env variables so these values don't need to be calculated again
echo "::set-env name=BUILD_FROM::${build_from}"
echo "::set-env name=BUILD_TO::${build_to}"
echo "::set-env name=DOCKERFILE::${dockerfile}"
echo "BUILD_FROM=${build_from}" >> $GITHUB_ENV
echo "BUILD_TO=${build_to}" >> $GITHUB_ENV
echo "DOCKERFILE=${dockerfile}" >> $GITHUB_ENV
echo "CACHE_TAG=${cache_tag}" >> $GITHUB_ENV
- name: Pull for cache
run: |
docker pull "${BUILD_TO}:latest" || true
docker pull "${BUILD_TO}:${CACHE_TAG}" || true
- name: Register QEMU binfmt
run: docker run --rm --privileged multiarch/qemu-user-static:5.0.0-2 --reset -p yes
- run: |
@@ -236,7 +245,7 @@ jobs:
--build-arg "BUILD_FROM=${BUILD_FROM}" \
--build-arg "BUILD_VERSION=${TAG}" \
--tag "${BUILD_TO}:${TAG}" \
--cache-from "${BUILD_TO}:latest" \
--cache-from "${BUILD_TO}:${CACHE_TAG}" \
--file "${DOCKERFILE}" \
.
- name: Log in to docker hub
@@ -270,7 +279,7 @@ jobs:
- name: Set TAG
run: |
TAG="${GITHUB_REF#refs/tags/v}"
echo "::set-env name=TAG::${TAG}"
echo "TAG=${TAG}" >> $GITHUB_ENV
- name: Log in to docker hub
env:
DOCKER_USER: ${{ secrets.DOCKER_USER }}
@@ -300,3 +309,19 @@ jobs:
esphome/esphome-amd64:${TAG} \
esphome/esphome-armv7:${TAG}
docker manifest push esphome/esphome:latest
deploy-hassio-repo:
if: github.repository == 'esphome/esphome'
runs-on: ubuntu-latest
needs: [deploy-docker]
steps:
- env:
TOKEN: ${{ secrets.DEPLOY_HASSIO_TOKEN }}
run: |
TAG="${GITHUB_REF#refs/tags/v}"
curl \
-u ":$TOKEN" \
-X POST \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/esphome/hassio/actions/workflows/bump-version.yml/dispatches \
-d "{\"ref\":\"master\",\"inputs\":{\"version\":\"$TAG\"}}"

4
.gitignore vendored
View File

@@ -81,7 +81,8 @@ venv.bak/
.pioenvs
.piolibdeps
.pio
.vscode
.vscode/
!.vscode/tasks.json
CMakeListsPrivate.txt
CMakeLists.txt
@@ -119,3 +120,4 @@ config/
tests/build/
tests/.esphome/
/.temp-clang-tidy.cpp
.pio/

11
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "run",
"type": "shell",
"command": "python3 -m esphome config dashboard",
"problemMatcher": []
}
]
}

View File

@@ -13,10 +13,13 @@ esphome/core/* @esphome/core
# Integrations
esphome/components/ac_dimmer/* @glmnet
esphome/components/adc/* @esphome/core
esphome/components/animation/* @syndlex
esphome/components/api/* @OttoWinter
esphome/components/async_tcp/* @OttoWinter
esphome/components/atc_mithermometer/* @ahpohl
esphome/components/bang_bang/* @OttoWinter
esphome/components/binary_sensor/* @esphome/core
esphome/components/canbus/* @danielschramm @mvturnho
esphome/components/captive_portal/* @OttoWinter
esphome/components/climate/* @esphome/core
esphome/components/climate_ir/* @glmnet
@@ -26,24 +29,37 @@ esphome/components/ct_clamp/* @jesserockz
esphome/components/debug/* @OttoWinter
esphome/components/dfplayer/* @glmnet
esphome/components/dht/* @OttoWinter
esphome/components/ds1307/* @badbadc0ffee
esphome/components/exposure_notifications/* @OttoWinter
esphome/components/ezo/* @ssieb
esphome/components/fastled_base/* @OttoWinter
esphome/components/globals/* @esphome/core
esphome/components/gpio/* @esphome/core
esphome/components/homeassistant/* @OttoWinter
esphome/components/i2c/* @esphome/core
esphome/components/inkplate6/* @jesserockz
esphome/components/integration/* @OttoWinter
esphome/components/interval/* @esphome/core
esphome/components/json/* @OttoWinter
esphome/components/ledc/* @OttoWinter
esphome/components/light/* @esphome/core
esphome/components/logger/* @esphome/core
esphome/components/mcp23s08/* @SenexCrenshaw
esphome/components/mcp23s17/* @SenexCrenshaw
esphome/components/mcp2515/* @danielschramm @mvturnho
esphome/components/mcp9808/* @k7hpn
esphome/components/network/* @esphome/core
esphome/components/nfc/* @jesserockz
esphome/components/ota/* @esphome/core
esphome/components/output/* @esphome/core
esphome/components/pid/* @OttoWinter
esphome/components/pn532/* @OttoWinter
esphome/components/pn532/* @OttoWinter @jesserockz
esphome/components/pn532_i2c/* @OttoWinter @jesserockz
esphome/components/pn532_spi/* @OttoWinter @jesserockz
esphome/components/power_supply/* @esphome/core
esphome/components/rc522/* @glmnet
esphome/components/rc522_i2c/* @glmnet
esphome/components/rc522_spi/* @glmnet
esphome/components/restart/* @esphome/core
esphome/components/rf_bridge/* @jesserockz
esphome/components/rtttl/* @glmnet
@@ -52,12 +68,28 @@ esphome/components/sensor/* @esphome/core
esphome/components/shutdown/* @esphome/core
esphome/components/sim800l/* @glmnet
esphome/components/spi/* @esphome/core
esphome/components/ssd1322_base/* @kbx81
esphome/components/ssd1322_spi/* @kbx81
esphome/components/ssd1325_base/* @kbx81
esphome/components/ssd1325_spi/* @kbx81
esphome/components/ssd1327_base/* @kbx81
esphome/components/ssd1327_i2c/* @kbx81
esphome/components/ssd1327_spi/* @kbx81
esphome/components/ssd1331_base/* @kbx81
esphome/components/ssd1331_spi/* @kbx81
esphome/components/ssd1351_base/* @kbx81
esphome/components/ssd1351_spi/* @kbx81
esphome/components/st7735/* @SenexCrenshaw
esphome/components/st7789v/* @kbx81
esphome/components/substitutions/* @esphome/core
esphome/components/sun/* @OttoWinter
esphome/components/switch/* @esphome/core
esphome/components/tcl112/* @glmnet
esphome/components/teleinfo/* @0hax
esphome/components/thermostat/* @kbx81
esphome/components/time/* @OttoWinter
esphome/components/tm1637/* @glmnet
esphome/components/tmp102/* @timsavage
esphome/components/tuya/binary_sensor/* @jesserockz
esphome/components/tuya/climate/* @jesserockz
esphome/components/tuya/sensor/* @jesserockz
@@ -67,3 +99,5 @@ esphome/components/ultrasonic/* @OttoWinter
esphome/components/version/* @esphome/core
esphome/components/web_server_base/* @OttoWinter
esphome/components/whirlpool/* @glmnet
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
esphome/components/xiaomi_mhoc401/* @vevsvevs

View File

@@ -1,5 +1,6 @@
include LICENSE
include README.md
include requirements.txt
include esphome/dashboard/templates/*.html
recursive-include esphome/dashboard/static *.ico *.js *.css *.woff* LICENSE
recursive-include esphome *.cpp *.h *.tcc

View File

@@ -1,4 +1,4 @@
ARG BUILD_FROM=esphome/esphome-base-amd64:2.4.0
ARG BUILD_FROM=esphome/esphome-base-amd64:2.6.0
FROM ${BUILD_FROM}
# First install requirements to leverage caching when requirements don't change
@@ -12,6 +12,13 @@ RUN pip3 install --no-cache-dir -e .
# Settings for dashboard
ENV USERNAME="" PASSWORD=""
# Expose the dashboard to Docker
EXPOSE 6052
# Run healthcheck (heartbeat)
HEALTHCHECK --interval=30s --timeout=30s \
CMD curl --fail http://localhost:6052 || exit 1
# The directory the user should mount their configuration files to
WORKDIR /config
# Set entrypoint to esphome so that the user doesn't have to type 'esphome'

View File

@@ -1,4 +1,4 @@
FROM esphome/esphome-base-amd64:2.4.0
FROM esphome/esphome-base-amd64:2.6.0
COPY . .

View File

@@ -1,4 +1,4 @@
FROM esphome/esphome-lint-base:2.4.0
FROM esphome/esphome-lint-base:2.6.0
COPY requirements.txt requirements_test.txt /
RUN pip3 install --no-cache-dir -r /requirements.txt -r /requirements_test.txt

View File

@@ -235,6 +235,9 @@ def setup_log(debug=False, quiet=False):
logging.getLogger('urllib3').setLevel(logging.WARNING)
try:
import colorama
colorama.init(strip=True)
from colorlog import ColoredFormatter
logging.getLogger().handlers[0].setFormatter(ColoredFormatter(
colorfmt,

View File

@@ -181,7 +181,7 @@ class APIClient(threading.Thread):
self._address)
_LOGGER.warning("(If this error persists, please set a static IP address: "
"https://esphome.io/components/wifi.html#manual-ips)")
raise APIConnectionError(err)
raise APIConnectionError(err) from err
_LOGGER.info("Connecting to %s:%s (%s)", self._address, self._port, ip)
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -346,12 +346,12 @@ class APIClient(threading.Thread):
raise APIConnectionError("No socket!")
try:
val = self._socket.recv(amount - len(ret))
except AttributeError:
raise APIConnectionError("Socket was closed")
except AttributeError as err:
raise APIConnectionError("Socket was closed") from err
except socket.timeout:
continue
except OSError as err:
raise APIConnectionError(f"Error while receiving data: {err}")
raise APIConnectionError(f"Error while receiving data: {err}") from err
ret += val
return ret

View File

@@ -84,6 +84,7 @@ def validate_automation(extra_schema=None, extra_validators=None, single=False):
return cv.Schema([schema])(value)
except cv.Invalid as err2:
if 'extra keys not allowed' in str(err2) and len(err2.path) == 2:
# pylint: disable=raise-missing-from
raise err
if 'Unable to find action' in str(err):
raise err2

View File

@@ -8,6 +8,9 @@ static const char *TAG = "ade7953";
void ADE7953::dump_config() {
ESP_LOGCONFIG(TAG, "ADE7953:");
if (this->has_irq_) {
ESP_LOGCONFIG(TAG, " IRQ Pin: GPIO%u", this->irq_pin_number_);
}
LOG_I2C_DEVICE(this);
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Voltage Sensor", this->voltage_sensor_);

View File

@@ -9,6 +9,10 @@ namespace ade7953 {
class ADE7953 : public i2c::I2CDevice, public PollingComponent {
public:
void set_irq_pin(uint8_t irq_pin) {
has_irq_ = true;
irq_pin_number_ = irq_pin;
}
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
void set_current_a_sensor(sensor::Sensor *current_a_sensor) { current_a_sensor_ = current_a_sensor; }
void set_current_b_sensor(sensor::Sensor *current_b_sensor) { current_b_sensor_ = current_b_sensor; }
@@ -20,6 +24,11 @@ class ADE7953 : public i2c::I2CDevice, public PollingComponent {
}
void setup() override {
if (this->has_irq_) {
auto pin = GPIOPin(this->irq_pin_number_, INPUT);
this->irq_pin_ = &pin;
this->irq_pin_->setup();
}
this->set_timeout(100, [this]() {
this->ade_write_<uint8_t>(0x0010, 0x04);
this->ade_write_<uint8_t>(0x00FE, 0xAD);
@@ -55,6 +64,9 @@ class ADE7953 : public i2c::I2CDevice, public PollingComponent {
return result;
}
bool has_irq_ = false;
uint8_t irq_pin_number_;
GPIOPin *irq_pin_{nullptr};
bool is_setup_{false};
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_a_sensor_{nullptr};

View File

@@ -1,14 +1,16 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, i2c
from esphome import pins
from esphome.const import CONF_ID, CONF_VOLTAGE, \
UNIT_VOLT, ICON_FLASH, UNIT_AMPERE, UNIT_WATT
DEPENDENCIES = ['i2c']
ace7953_ns = cg.esphome_ns.namespace('ade7953')
ADE7953 = ace7953_ns.class_('ADE7953', cg.PollingComponent, i2c.I2CDevice)
ade7953_ns = cg.esphome_ns.namespace('ade7953')
ADE7953 = ade7953_ns.class_('ADE7953', cg.PollingComponent, i2c.I2CDevice)
CONF_IRQ_PIN = 'irq_pin'
CONF_CURRENT_A = 'current_a'
CONF_CURRENT_B = 'current_b'
CONF_ACTIVE_POWER_A = 'active_power_a'
@@ -16,7 +18,7 @@ CONF_ACTIVE_POWER_B = 'active_power_b'
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(ADE7953),
cv.Optional(CONF_IRQ_PIN): pins.input_pin,
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 1),
cv.Optional(CONF_CURRENT_A): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2),
cv.Optional(CONF_CURRENT_B): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2),
@@ -30,6 +32,9 @@ def to_code(config):
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
if CONF_IRQ_PIN in config:
cg.add(var.set_irq_pin(config[CONF_IRQ_PIN]))
for key in [CONF_VOLTAGE, CONF_CURRENT_A, CONF_CURRENT_B, CONF_ACTIVE_POWER_A,
CONF_ACTIVE_POWER_B]:
if key not in config:

View File

@@ -0,0 +1,94 @@
import logging
from esphome import core
from esphome.components import display, font
import esphome.components.image as espImage
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_FILE, CONF_ID, CONF_TYPE, CONF_RESIZE
from esphome.core import CORE, HexInt
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['display']
MULTI_CONF = True
Animation_ = display.display_ns.class_('Animation')
CONF_RAW_DATA_ID = 'raw_data_id'
ANIMATION_SCHEMA = cv.Schema({
cv.Required(CONF_ID): cv.declare_id(Animation_),
cv.Required(CONF_FILE): cv.file_,
cv.Optional(CONF_RESIZE): cv.dimensions,
cv.Optional(CONF_TYPE, default='BINARY'): cv.enum(espImage.IMAGE_TYPE, upper=True),
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
})
CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA)
CODEOWNERS = ['@syndlex']
def to_code(config):
from PIL import Image
path = CORE.relative_config_path(config[CONF_FILE])
try:
image = Image.open(path)
except Exception as e:
raise core.EsphomeError(f"Could not load image file {path}: {e}")
width, height = image.size
frames = image.n_frames
if CONF_RESIZE in config:
image.thumbnail(config[CONF_RESIZE])
width, height = image.size
else:
if width > 500 or height > 500:
_LOGGER.warning("The image you requested is very big. Please consider using"
" the resize parameter.")
if config[CONF_TYPE] == 'GRAYSCALE':
data = [0 for _ in range(height * width * frames)]
pos = 0
for frameIndex in range(frames):
image.seek(frameIndex)
frame = image.convert('L', dither=Image.NONE)
pixels = list(frame.getdata())
for pix in pixels:
data[pos] = pix
pos += 1
elif config[CONF_TYPE] == 'RGB24':
data = [0 for _ in range(height * width * 3 * frames)]
pos = 0
for frameIndex in range(frames):
image.seek(frameIndex)
frame = image.convert('RGB')
pixels = list(frame.getdata())
for pix in pixels:
data[pos] = pix[0]
pos += 1
data[pos] = pix[1]
pos += 1
data[pos] = pix[2]
pos += 1
elif config[CONF_TYPE] == 'BINARY':
width8 = ((width + 7) // 8) * 8
data = [0 for _ in range((height * width8 // 8) * frames)]
for frameIndex in range(frames):
image.seek(frameIndex)
frame = image.convert('1', dither=Image.NONE)
for y in range(height):
for x in range(width):
if frame.getpixel((x, y)):
continue
pos = x + y * width8 + (height * width8 * frameIndex)
data[pos // 8] |= 0x80 >> (pos % 8)
rhs = [HexInt(x) for x in data]
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, frames,
espImage.IMAGE_TYPE[config[CONF_TYPE]])

View File

@@ -3,7 +3,8 @@ import esphome.config_validation as cv
from esphome import automation
from esphome.automation import Condition
from esphome.const import CONF_DATA, CONF_DATA_TEMPLATE, CONF_ID, CONF_PASSWORD, CONF_PORT, \
CONF_REBOOT_TIMEOUT, CONF_SERVICE, CONF_VARIABLES, CONF_SERVICES, CONF_TRIGGER_ID, CONF_EVENT
CONF_REBOOT_TIMEOUT, CONF_SERVICE, CONF_VARIABLES, CONF_SERVICES, CONF_TRIGGER_ID, CONF_EVENT, \
CONF_TAG
from esphome.core import coroutine_with_priority
DEPENDENCIES = ['network']
@@ -137,6 +138,23 @@ def homeassistant_event_to_code(config, action_id, template_arg, args):
yield var
HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value({
cv.GenerateID(): cv.use_id(APIServer),
cv.Required(CONF_TAG): cv.templatable(cv.string_strict),
}, key=CONF_TAG)
@automation.register_action('homeassistant.tag_scanned', HomeAssistantServiceCallAction,
HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA)
def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args):
serv = yield cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, serv, True)
cg.add(var.set_service('esphome.tag_scanned'))
templ = yield cg.templatable(config[CONF_TAG], args, cg.std_string)
cg.add(var.add_data('tag_id', templ))
yield var
@automation.register_condition('api.connected', APIConnectedCondition, {})
def api_connected_to_code(config, condition_id, template_arg, args):
yield cg.new_Pvariable(condition_id, template_arg)

View File

@@ -679,7 +679,7 @@ enum ClimateSwingMode {
CLIMATE_SWING_OFF = 0;
CLIMATE_SWING_BOTH = 1;
CLIMATE_SWING_VERTICAL = 2;
CLIMATE_SWINT_HORIZONTAL = 3;
CLIMATE_SWING_HORIZONTAL = 3;
}
enum ClimateAction {
CLIMATE_ACTION_OFF = 0;

View File

@@ -676,8 +676,10 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type)
}
}
this->client_->add(reinterpret_cast<char *>(header.data()), header.size());
this->client_->add(reinterpret_cast<char *>(buffer.get_buffer()->data()), buffer.get_buffer()->size());
this->client_->add(reinterpret_cast<char *>(header.data()), header.size(),
ASYNC_WRITE_FLAG_COPY | ASYNC_WRITE_FLAG_MORE);
this->client_->add(reinterpret_cast<char *>(buffer.get_buffer()->data()), buffer.get_buffer()->size(),
ASYNC_WRITE_FLAG_COPY);
bool ret = this->client_->send();
return ret;
}

View File

@@ -154,8 +154,8 @@ template<> const char *proto_enum_to_string<enums::ClimateSwingMode>(enums::Clim
return "CLIMATE_SWING_BOTH";
case enums::CLIMATE_SWING_VERTICAL:
return "CLIMATE_SWING_VERTICAL";
case enums::CLIMATE_SWINT_HORIZONTAL:
return "CLIMATE_SWINT_HORIZONTAL";
case enums::CLIMATE_SWING_HORIZONTAL:
return "CLIMATE_SWING_HORIZONTAL";
default:
return "UNKNOWN";
}

View File

@@ -74,7 +74,7 @@ enum ClimateSwingMode : uint32_t {
CLIMATE_SWING_OFF = 0,
CLIMATE_SWING_BOTH = 1,
CLIMATE_SWING_VERTICAL = 2,
CLIMATE_SWINT_HORIZONTAL = 3,
CLIMATE_SWING_HORIZONTAL = 3,
};
enum ClimateAction : uint32_t {
CLIMATE_ACTION_OFF = 0,

View File

@@ -62,8 +62,7 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
error = true;
break;
}
uint32_t val = (uint32_t(buffer[i]) << 0) | (uint32_t(buffer[i + 1]) << 8) | (uint32_t(buffer[i + 2]) << 16) |
(uint32_t(buffer[i + 3]) << 24);
uint32_t val = encode_uint32(buffer[i + 3], buffer[i + 2], buffer[i + 1], buffer[i]);
if (!this->decode_32bit(field_id, Proto32Bit(val))) {
ESP_LOGV(TAG, "Cannot decode 32-bit field %u with value %u!", field_id, val);
}

View File

@@ -12,4 +12,4 @@ def to_code(config):
cg.add_library('AsyncTCP-esphome', '1.1.1')
elif CORE.is_esp8266:
# https://github.com/OttoWinter/ESPAsyncTCP
cg.add_library('ESPAsyncTCP-esphome', '1.2.2')
cg.add_library('ESPAsyncTCP-esphome', '1.2.3')

View File

@@ -0,0 +1,137 @@
#include "atc_mithermometer.h"
#include "esphome/core/log.h"
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace atc_mithermometer {
static const char *TAG = "atc_mithermometer";
void ATCMiThermometer::dump_config() {
ESP_LOGCONFIG(TAG, "ATC MiThermometer");
LOG_SENSOR(" ", "Temperature", this->temperature_);
LOG_SENSOR(" ", "Humidity", this->humidity_);
LOG_SENSOR(" ", "Battery Level", this->battery_level_);
LOG_SENSOR(" ", "Battery Voltage", this->battery_voltage_);
}
bool ATCMiThermometer::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
if (device.address_uint64() != this->address_) {
ESP_LOGVV(TAG, "parse_device(): unknown MAC address.");
return false;
}
ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str());
bool success = false;
for (auto &service_data : device.get_service_datas()) {
auto res = parse_header(service_data);
if (res->is_duplicate) {
continue;
}
if (!(parse_message(service_data.data, *res))) {
continue;
}
if (!(report_results(res, device.address_str()))) {
continue;
}
if (res->temperature.has_value() && this->temperature_ != nullptr)
this->temperature_->publish_state(*res->temperature);
if (res->humidity.has_value() && this->humidity_ != nullptr)
this->humidity_->publish_state(*res->humidity);
if (res->battery_level.has_value() && this->battery_level_ != nullptr)
this->battery_level_->publish_state(*res->battery_level);
if (res->battery_voltage.has_value() && this->battery_voltage_ != nullptr)
this->battery_voltage_->publish_state(*res->battery_voltage);
success = true;
}
if (!success) {
return false;
}
return true;
}
optional<ParseResult> ATCMiThermometer::parse_header(const esp32_ble_tracker::ServiceData &service_data) {
ParseResult result;
if (!service_data.uuid.contains(0x1A, 0x18)) {
ESP_LOGVV(TAG, "parse_header(): no service data UUID magic bytes.");
return {};
}
auto raw = service_data.data;
static uint8_t last_frame_count = 0;
if (last_frame_count == raw[12]) {
ESP_LOGVV(TAG, "parse_header(): duplicate data packet received (%d).", static_cast<int>(last_frame_count));
result.is_duplicate = true;
return {};
}
last_frame_count = raw[12];
result.is_duplicate = false;
return result;
}
bool ATCMiThermometer::parse_message(const std::vector<uint8_t> &message, ParseResult &result) {
// Byte 0-5 mac in correct order
// Byte 6-7 Temperature in uint16
// Byte 8 Humidity in percent
// Byte 9 Battery in percent
// Byte 10-11 Battery in mV uint16_t
// Byte 12 frame packet counter
const uint8_t *data = message.data();
const int data_length = 13;
if (message.size() != data_length) {
ESP_LOGVV(TAG, "parse_message(): payload has wrong size (%d)!", message.size());
return false;
}
// temperature, 2 bytes, 16-bit signed integer (LE), 0.1 °C
const int16_t temperature = uint16_t(data[7]) | (uint16_t(data[6]) << 8);
result.temperature = temperature / 10.0f;
// humidity, 1 byte, 8-bit unsigned integer, 1.0 %
result.humidity = data[8];
// battery, 1 byte, 8-bit unsigned integer, 1.0 %
result.battery_level = data[9];
// battery, 2 bytes, 16-bit unsigned integer, 0.001 V
const int16_t battery_voltage = uint16_t(data[11]) | (uint16_t(data[10]) << 8);
result.battery_voltage = battery_voltage / 1.0e3f;
return true;
}
bool ATCMiThermometer::report_results(const optional<ParseResult> &result, const std::string &address) {
if (!result.has_value()) {
ESP_LOGVV(TAG, "report_results(): no results available.");
return false;
}
ESP_LOGD(TAG, "Got ATC MiThermometer (%s):", address.c_str());
if (result->temperature.has_value()) {
ESP_LOGD(TAG, " Temperature: %.1f °C", *result->temperature);
}
if (result->humidity.has_value()) {
ESP_LOGD(TAG, " Humidity: %.0f %%", *result->humidity);
}
if (result->battery_level.has_value()) {
ESP_LOGD(TAG, " Battery Level: %.0f %%", *result->battery_level);
}
if (result->battery_voltage.has_value()) {
ESP_LOGD(TAG, " Battery Voltage: %.3f V", *result->battery_voltage);
}
return true;
}
} // namespace atc_mithermometer
} // namespace esphome
#endif

View File

@@ -0,0 +1,48 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace atc_mithermometer {
struct ParseResult {
optional<float> temperature;
optional<float> humidity;
optional<float> battery_level;
optional<float> battery_voltage;
bool is_duplicate;
int raw_offset;
};
class ATCMiThermometer : public Component, public esp32_ble_tracker::ESPBTDeviceListener {
public:
void set_address(uint64_t address) { address_ = address; };
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; }
void set_battery_voltage(sensor::Sensor *battery_voltage) { battery_voltage_ = battery_voltage; }
protected:
uint64_t address_;
sensor::Sensor *temperature_{nullptr};
sensor::Sensor *humidity_{nullptr};
sensor::Sensor *battery_level_{nullptr};
sensor::Sensor *battery_voltage_{nullptr};
optional<ParseResult> parse_header(const esp32_ble_tracker::ServiceData &service_data);
bool parse_message(const std::vector<uint8_t> &message, ParseResult &result);
bool report_results(const optional<ParseResult> &result, const std::string &address);
};
} // namespace atc_mithermometer
} // namespace esphome
#endif

View File

@@ -0,0 +1,45 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor, esp32_ble_tracker
from esphome.const import CONF_BATTERY_LEVEL, CONF_BATTERY_VOLTAGE, CONF_MAC_ADDRESS, \
CONF_HUMIDITY, CONF_TEMPERATURE, CONF_ID, UNIT_CELSIUS, UNIT_PERCENT, UNIT_VOLT, \
ICON_BATTERY, ICON_THERMOMETER, ICON_WATER_PERCENT
CODEOWNERS = ['@ahpohl']
DEPENDENCIES = ['esp32_ble_tracker']
atc_mithermometer_ns = cg.esphome_ns.namespace('atc_mithermometer')
ATCMiThermometer = atc_mithermometer_ns.class_('ATCMiThermometer',
esp32_ble_tracker.ESPBTDeviceListener,
cg.Component)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(ATCMiThermometer),
cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1),
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 0),
cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(UNIT_PERCENT, ICON_BATTERY, 0),
cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_BATTERY, 3),
}).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA).extend(cv.COMPONENT_SCHEMA)
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield esp32_ble_tracker.register_ble_device(var, config)
cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
if CONF_TEMPERATURE in config:
sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
cg.add(var.set_temperature(sens))
if CONF_HUMIDITY in config:
sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
cg.add(var.set_humidity(sens))
if CONF_BATTERY_LEVEL in config:
sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL])
cg.add(var.set_battery_level(sens))
if CONF_BATTERY_VOLTAGE in config:
sens = yield sensor.new_sensor(config[CONF_BATTERY_VOLTAGE])
cg.add(var.set_battery_voltage(sens))

View File

@@ -104,6 +104,7 @@ def parse_multi_click_timing_str(value):
try:
state = cv.boolean(parts[0])
except cv.Invalid:
# pylint: disable=raise-missing-from
raise cv.Invalid("First word must either be ON or OFF, not {}".format(parts[0]))
if parts[1] != 'for':

View File

@@ -0,0 +1,124 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.core import CORE, coroutine
from esphome.const import CONF_ID, CONF_TRIGGER_ID, CONF_DATA
CODEOWNERS = ['@mvturnho', '@danielschramm']
IS_PLATFORM_COMPONENT = True
CONF_CAN_ID = 'can_id'
CONF_USE_EXTENDED_ID = 'use_extended_id'
CONF_CANBUS_ID = 'canbus_id'
CONF_BIT_RATE = 'bit_rate'
CONF_ON_FRAME = 'on_frame'
CONF_CANBUS_SEND = 'canbus.send'
def validate_id(id_value, id_ext):
if not id_ext:
if id_value > 0x7ff:
raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
def validate_raw_data(value):
if isinstance(value, str):
return value.encode('utf-8')
if isinstance(value, list):
return cv.Schema([cv.hex_uint8_t])(value)
raise cv.Invalid("data must either be a string wrapped in quotes or a list of bytes")
canbus_ns = cg.esphome_ns.namespace('canbus')
CanbusComponent = canbus_ns.class_('CanbusComponent', cg.Component)
CanbusTrigger = canbus_ns.class_('CanbusTrigger',
automation.Trigger.template(cg.std_vector.template(cg.uint8)),
cg.Component)
CanSpeed = canbus_ns.enum('CAN_SPEED')
CAN_SPEEDS = {
'5KBPS': CanSpeed.CAN_5KBPS,
'10KBPS': CanSpeed.CAN_10KBPS,
'20KBPS': CanSpeed.CAN_20KBPS,
'31K25BPS': CanSpeed.CAN_31K25BPS,
'33KBPS': CanSpeed.CAN_33KBPS,
'40KBPS': CanSpeed.CAN_40KBPS,
'50KBPS': CanSpeed.CAN_50KBPS,
'80KBPS': CanSpeed.CAN_80KBPS,
'83K3BPS': CanSpeed.CAN_83K3BPS,
'95KBPS': CanSpeed.CAN_95KBPS,
'100KBPS': CanSpeed.CAN_100KBPS,
'125KBPS': CanSpeed.CAN_125KBPS,
'200KBPS': CanSpeed.CAN_200KBPS,
'250KBPS': CanSpeed.CAN_250KBPS,
'500KBPS': CanSpeed.CAN_500KBPS,
'1000KBPS': CanSpeed.CAN_1000KBPS,
}
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(CanbusComponent),
cv.Required(CONF_CAN_ID): cv.int_range(min=0, max=0x1fffffff),
cv.Optional(CONF_BIT_RATE, default='125KBPS'): cv.enum(CAN_SPEEDS, upper=True),
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
cv.Optional(CONF_ON_FRAME): automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CanbusTrigger),
cv.GenerateID(CONF_CAN_ID): cv.int_range(min=0, max=0x1fffffff),
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
}),
}).extend(cv.COMPONENT_SCHEMA)
@coroutine
def setup_canbus_core_(var, config):
validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID])
yield cg.register_component(var, config)
cg.add(var.set_can_id([config[CONF_CAN_ID]]))
cg.add(var.set_use_extended_id([config[CONF_USE_EXTENDED_ID]]))
cg.add(var.set_bitrate(CAN_SPEEDS[config[CONF_BIT_RATE]]))
for conf in config.get(CONF_ON_FRAME, []):
can_id = conf[CONF_CAN_ID]
ext_id = conf[CONF_USE_EXTENDED_ID]
validate_id(can_id, ext_id)
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, can_id, ext_id)
yield cg.register_component(trigger, conf)
yield automation.build_automation(trigger, [(cg.std_vector.template(cg.uint8), 'x')], conf)
@coroutine
def register_canbus(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.new_Pvariable(config[CONF_ID], var)
yield setup_canbus_core_(var, config)
# Actions
@automation.register_action(CONF_CANBUS_SEND,
canbus_ns.class_('CanbusSendAction', automation.Action),
cv.maybe_simple_value({
cv.GenerateID(CONF_CANBUS_ID): cv.use_id(CanbusComponent),
cv.Optional(CONF_CAN_ID): cv.int_range(min=0, max=0x1fffffff),
cv.Optional(CONF_USE_EXTENDED_ID, default=False): cv.boolean,
cv.Required(CONF_DATA): cv.templatable(validate_raw_data),
}, key=CONF_DATA))
def canbus_action_to_code(config, action_id, template_arg, args):
validate_id(config[CONF_CAN_ID], config[CONF_USE_EXTENDED_ID])
var = cg.new_Pvariable(action_id, template_arg)
yield cg.register_parented(var, config[CONF_CANBUS_ID])
if CONF_CAN_ID in config:
can_id = yield cg.templatable(config[CONF_CAN_ID], args, cg.uint32)
cg.add(var.set_can_id(can_id))
use_extended_id = yield cg.templatable(config[CONF_USE_EXTENDED_ID], args, cg.uint32)
cg.add(var.set_use_extended_id(use_extended_id))
data = config[CONF_DATA]
if isinstance(data, bytes):
data = [int(x) for x in data]
if cg.is_template(data):
templ = yield cg.templatable(data, args, cg.std_vector.template(cg.uint8))
cg.add(var.set_data_template(templ))
else:
cg.add(var.set_data_static(data))
yield var

View File

@@ -0,0 +1,87 @@
#include "canbus.h"
#include "esphome/core/log.h"
namespace esphome {
namespace canbus {
static const char *TAG = "canbus";
void Canbus::setup() {
ESP_LOGCONFIG(TAG, "Setting up Canbus...");
if (!this->setup_internal()) {
ESP_LOGE(TAG, "setup error!");
this->mark_failed();
}
}
void Canbus::dump_config() {
if (this->use_extended_id_) {
ESP_LOGCONFIG(TAG, "config extended id=0x%08x", this->can_id_);
} else {
ESP_LOGCONFIG(TAG, "config standard id=0x%03x", this->can_id_);
}
}
void Canbus::send_data(uint32_t can_id, bool use_extended_id, const std::vector<uint8_t> &data) {
struct CanFrame can_message;
uint8_t size = static_cast<uint8_t>(data.size());
if (use_extended_id) {
ESP_LOGD(TAG, "send extended id=0x%08x size=%d", can_id, size);
} else {
ESP_LOGD(TAG, "send extended id=0x%03x size=%d", can_id, size);
}
if (size > CAN_MAX_DATA_LENGTH)
size = CAN_MAX_DATA_LENGTH;
can_message.can_data_length_code = size;
can_message.can_id = can_id;
can_message.use_extended_id = use_extended_id;
for (int i = 0; i < size; i++) {
can_message.data[i] = data[i];
ESP_LOGVV(TAG, " data[%d]=%02x", i, can_message.data[i]);
}
this->send_message(&can_message);
}
void Canbus::add_trigger(CanbusTrigger *trigger) {
if (trigger->use_extended_id_) {
ESP_LOGVV(TAG, "add trigger for extended canid=0x%08x", trigger->can_id_);
} else {
ESP_LOGVV(TAG, "add trigger for std canid=0x%03x", trigger->can_id_);
}
this->triggers_.push_back(trigger);
};
void Canbus::loop() {
struct CanFrame can_message;
// readmessage
if (this->read_message(&can_message) == canbus::ERROR_OK) {
if (can_message.use_extended_id) {
ESP_LOGD(TAG, "received can message extended can_id=0x%x size=%d", can_message.can_id,
can_message.can_data_length_code);
} else {
ESP_LOGD(TAG, "received can message std can_id=0x%x size=%d", can_message.can_id,
can_message.can_data_length_code);
}
std::vector<uint8_t> data;
// show data received
for (int i = 0; i < can_message.can_data_length_code; i++) {
ESP_LOGV(TAG, " can_message.data[%d]=%02x", i, can_message.data[i]);
data.push_back(can_message.data[i]);
}
// fire all triggers
for (auto trigger : this->triggers_) {
if ((trigger->can_id_ == can_message.can_id) && (trigger->use_extended_id_ == can_message.use_extended_id)) {
trigger->trigger(data);
}
}
}
}
} // namespace canbus
} // namespace esphome

View File

@@ -0,0 +1,134 @@
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/optional.h"
namespace esphome {
namespace canbus {
enum Error : uint8_t {
ERROR_OK = 0,
ERROR_FAIL = 1,
ERROR_ALLTXBUSY = 2,
ERROR_FAILINIT = 3,
ERROR_FAILTX = 4,
ERROR_NOMSG = 5
};
enum CanSpeed : uint8_t {
CAN_5KBPS,
CAN_10KBPS,
CAN_20KBPS,
CAN_31K25BPS,
CAN_33KBPS,
CAN_40KBPS,
CAN_50KBPS,
CAN_80KBPS,
CAN_83K3BPS,
CAN_95KBPS,
CAN_100KBPS,
CAN_125KBPS,
CAN_200KBPS,
CAN_250KBPS,
CAN_500KBPS,
CAN_1000KBPS
};
class CanbusTrigger;
template<typename... Ts> class CanbusSendAction;
/* CAN payload length definitions according to ISO 11898-1 */
static const uint8_t CAN_MAX_DATA_LENGTH = 8;
/*
Can Frame describes a normative CAN Frame
The RTR = Remote Transmission Request is implemented in every CAN controller but rarely used
So currently the flag is passed to and from the hardware but currently ignored to the user application.
*/
struct CanFrame {
bool use_extended_id = false;
bool remote_transmission_request = false;
uint32_t can_id; /* 29 or 11 bit CAN_ID */
uint8_t can_data_length_code; /* frame payload length in byte (0 .. CAN_MAX_DATA_LENGTH) */
uint8_t data[CAN_MAX_DATA_LENGTH] __attribute__((aligned(8)));
};
class Canbus : public Component {
public:
Canbus(){};
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::HARDWARE; }
void loop() override;
void send_data(uint32_t can_id, bool use_extended_id, const std::vector<uint8_t> &data);
void set_can_id(uint32_t can_id) { this->can_id_ = can_id; }
void set_use_extended_id(bool use_extended_id) { this->use_extended_id_ = use_extended_id; }
void set_bitrate(CanSpeed bit_rate) { this->bit_rate_ = bit_rate; }
void add_trigger(CanbusTrigger *trigger);
protected:
template<typename... Ts> friend class CanbusSendAction;
std::vector<CanbusTrigger *> triggers_{};
uint32_t can_id_;
bool use_extended_id_;
CanSpeed bit_rate_;
virtual bool setup_internal();
virtual Error send_message(struct CanFrame *frame);
virtual Error read_message(struct CanFrame *frame);
};
template<typename... Ts> class CanbusSendAction : public Action<Ts...>, public Parented<Canbus> {
public:
void set_data_template(const std::function<std::vector<uint8_t>(Ts...)> func) {
this->data_func_ = func;
this->static_ = false;
}
void set_data_static(const std::vector<uint8_t> &data) {
this->data_static_ = data;
this->static_ = true;
}
void set_can_id(uint32_t can_id) { this->can_id_ = can_id; }
void set_use_extended_id(bool use_extended_id) { this->use_extended_id_ = use_extended_id; }
void play(Ts... x) override {
auto can_id = this->can_id_.has_value() ? *this->can_id_ : this->parent_->can_id_;
auto use_extended_id =
this->use_extended_id_.has_value() ? *this->use_extended_id_ : this->parent_->use_extended_id_;
if (this->static_) {
this->parent_->send_data(can_id, use_extended_id, this->data_static_);
} else {
auto val = this->data_func_(x...);
this->parent_->send_data(can_id, use_extended_id, val);
}
}
protected:
optional<uint32_t> can_id_{};
optional<bool> use_extended_id_{};
bool static_{false};
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
std::vector<uint8_t> data_static_{};
};
class CanbusTrigger : public Trigger<std::vector<uint8_t>>, public Component {
friend class Canbus;
public:
explicit CanbusTrigger(Canbus *parent, const std::uint32_t can_id, const bool use_extended_id)
: parent_(parent), can_id_(can_id), use_extended_id_(use_extended_id){};
void setup() override { this->parent_->add_trigger(this); }
protected:
Canbus *parent_;
uint32_t can_id_;
bool use_extended_id_;
};
} // namespace canbus
} // namespace esphome

View File

@@ -102,10 +102,14 @@ void CCS811Component::send_env_data_() {
// temperature has a 25° offset to allow negative temperatures
temperature += 25;
// only 0.5 fractions are supported (application note)
auto hum_value = static_cast<uint8_t>(roundf(humidity * 2));
auto temp_value = static_cast<uint8_t>(roundf(temperature * 2));
this->write_bytes(0x05, {hum_value, 0x00, temp_value, 0x00});
// At page 18 of:
// https://cdn.sparkfun.com/datasheets/BreakoutBoards/CCS811_Programming_Guide.pdf
// Reference code:
// https://github.com/adafruit/Adafruit_CCS811/blob/0990f5c620354d8bc087c4706bec091d8e6e5dfd/Adafruit_CCS811.cpp#L135-L142
uint16_t hum_conv = static_cast<uint16_t>(lroundf(humidity * 512.0f + 0.5f));
uint16_t temp_conv = static_cast<uint16_t>(lroundf(temperature * 512.0f + 0.5f));
this->write_bytes(0x05, {(uint8_t)((hum_conv >> 8) & 0xff), (uint8_t)((hum_conv & 0xff)),
(uint8_t)((temp_conv >> 8) & 0xff), (uint8_t)((temp_conv & 0xff))});
}
void CCS811Component::dump_config() {
ESP_LOGCONFIG(TAG, "CCS811");

View File

@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_ID, ICON_RADIATOR, UNIT_PARTS_PER_MILLION, \
UNIT_PARTS_PER_BILLION, CONF_TEMPERATURE, CONF_HUMIDITY, ICON_PERIODIC_TABLE_CO2
UNIT_PARTS_PER_BILLION, CONF_TEMPERATURE, CONF_HUMIDITY, ICON_MOLECULE_CO2
DEPENDENCIES = ['i2c']
@@ -15,7 +15,7 @@ CONF_BASELINE = 'baseline'
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(CCS811Component),
cv.Required(CONF_ECO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION, ICON_PERIODIC_TABLE_CO2,
cv.Required(CONF_ECO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION, ICON_MOLECULE_CO2,
0),
cv.Required(CONF_TVOC): sensor.sensor_schema(UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0),

View File

@@ -12,8 +12,10 @@ void DaikinClimate::transmit_state() {
0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00};
remote_state[21] = this->operation_mode_();
remote_state[24] = this->fan_speed_();
remote_state[22] = this->temperature_();
uint16_t fan_speed = this->fan_speed_();
remote_state[24] = fan_speed >> 8;
remote_state[25] = fan_speed & 0xff;
// Calculate checksum
for (int i = 16; i < 34; i++) {
@@ -90,25 +92,38 @@ uint8_t DaikinClimate::operation_mode_() {
return operating_mode;
}
uint8_t DaikinClimate::fan_speed_() {
uint8_t fan_speed;
uint16_t DaikinClimate::fan_speed_() {
uint16_t fan_speed;
switch (this->fan_mode) {
case climate::CLIMATE_FAN_LOW:
fan_speed = DAIKIN_FAN_1;
fan_speed = DAIKIN_FAN_1 << 8;
break;
case climate::CLIMATE_FAN_MEDIUM:
fan_speed = DAIKIN_FAN_3;
fan_speed = DAIKIN_FAN_3 << 8;
break;
case climate::CLIMATE_FAN_HIGH:
fan_speed = DAIKIN_FAN_5;
fan_speed = DAIKIN_FAN_5 << 8;
break;
case climate::CLIMATE_FAN_AUTO:
default:
fan_speed = DAIKIN_FAN_AUTO;
fan_speed = DAIKIN_FAN_AUTO << 8;
}
// If swing is enabled switch first 4 bits to 1111
return this->swing_mode == climate::CLIMATE_SWING_VERTICAL ? fan_speed | 0xF : fan_speed;
switch (this->swing_mode) {
case climate::CLIMATE_SWING_VERTICAL:
fan_speed |= 0x0F00;
break;
case climate::CLIMATE_SWING_HORIZONTAL:
fan_speed |= 0x000F;
break;
case climate::CLIMATE_SWING_BOTH:
fan_speed |= 0x0F0F;
break;
default:
break;
}
return fan_speed;
}
uint8_t DaikinClimate::temperature_() {
@@ -159,13 +174,19 @@ bool DaikinClimate::parse_state_frame_(const uint8_t frame[]) {
this->target_temperature = temperature >> 1;
}
uint8_t fan_mode = frame[8];
if (fan_mode & 0xF)
uint8_t swing_mode = frame[9];
if (fan_mode & 0xF && swing_mode & 0xF)
this->swing_mode = climate::CLIMATE_SWING_BOTH;
else if (fan_mode & 0xF)
this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
else if (swing_mode & 0xF)
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
else
this->swing_mode = climate::CLIMATE_SWING_OFF;
switch (fan_mode & 0xF0) {
case DAIKIN_FAN_1:
case DAIKIN_FAN_2:
case DAIKIN_FAN_SILENT:
this->fan_mode = climate::CLIMATE_FAN_LOW;
break;
case DAIKIN_FAN_3:

View File

@@ -21,6 +21,7 @@ const uint8_t DAIKIN_MODE_ON = 0x01;
// Fan Speed
const uint8_t DAIKIN_FAN_AUTO = 0xA0;
const uint8_t DAIKIN_FAN_SILENT = 0xB0;
const uint8_t DAIKIN_FAN_1 = 0x30;
const uint8_t DAIKIN_FAN_2 = 0x40;
const uint8_t DAIKIN_FAN_3 = 0x50;
@@ -46,13 +47,14 @@ class DaikinClimate : public climate_ir::ClimateIR {
DAIKIN_TEMP_MIN, DAIKIN_TEMP_MAX, 1.0f, true, true,
std::vector<climate::ClimateFanMode>{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW,
climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH},
std::vector<climate::ClimateSwingMode>{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {}
std::vector<climate::ClimateSwingMode>{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL,
climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}) {}
protected:
// Transmit via IR the state of this climate controller.
void transmit_state() override;
uint8_t operation_mode_();
uint8_t fan_speed_();
uint16_t fan_speed_();
uint8_t temperature_();
// Handle received IR Buffer
bool on_receive(remote_base::RemoteReceiveData data) override;

View File

@@ -32,19 +32,19 @@ void DHT::dump_config() {
void DHT::update() {
float temperature, humidity;
bool error;
bool success;
if (this->model_ == DHT_MODEL_AUTO_DETECT) {
this->model_ = DHT_MODEL_DHT22;
error = this->read_sensor_(&temperature, &humidity, false);
if (error) {
success = this->read_sensor_(&temperature, &humidity, false);
if (!success) {
this->model_ = DHT_MODEL_DHT11;
return;
}
} else {
error = this->read_sensor_(&temperature, &humidity, true);
success = this->read_sensor_(&temperature, &humidity, true);
}
if (error) {
if (success) {
ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%%", temperature, humidity);
if (this->temperature_sensor_ != nullptr)

View File

@@ -204,31 +204,33 @@ void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign al
if (ret > 0)
this->print(x, y, font, color, align, buffer);
}
void DisplayBuffer::image(int x, int y, Image *image) { this->image(x, y, COLOR_ON, image); }
void DisplayBuffer::image(int x, int y, Color color, Image *image, bool invert) {
if (image->get_type() == BINARY) {
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
if (invert)
this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? COLOR_OFF : color);
else
this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? color : COLOR_OFF);
void DisplayBuffer::image(int x, int y, Image *image, Color color_on, Color color_off) {
switch (image->get_type()) {
case IMAGE_TYPE_BINARY:
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? color_on : color_off);
}
}
}
} else if (image->get_type() == GRAYSCALE) {
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale_pixel(img_x, img_y));
break;
case IMAGE_TYPE_GRAYSCALE:
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale_pixel(img_x, img_y));
}
}
}
} else if (image->get_type() == RGB) {
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
this->draw_pixel_at(x + img_x, y + img_y, image->get_color_pixel(img_x, img_y));
break;
case IMAGE_TYPE_RGB24:
for (int img_x = 0; img_x < image->get_width(); img_x++) {
for (int img_y = 0; img_y < image->get_height(); img_y++) {
this->draw_pixel_at(x + img_x, y + img_y, image->get_color_pixel(img_x, img_y));
}
}
}
break;
}
}
void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1,
int *width, int *height) {
int x_offset, baseline;
@@ -297,7 +299,7 @@ void DisplayBuffer::printf(int x, int y, Font *font, TextAlign align, const char
void DisplayBuffer::printf(int x, int y, Font *font, const char *format, ...) {
va_list arg;
va_start(arg, format);
this->vprintf_(x, y, font, COLOR_ON, TextAlign::CENTER_LEFT, format, arg);
this->vprintf_(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, arg);
va_end(arg);
}
void DisplayBuffer::set_writer(display_writer_t &&writer) { this->writer_ = writer; }
@@ -463,15 +465,59 @@ Color Image::get_grayscale_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return 0;
const uint32_t pos = (x + y * this->width_);
return Color(pgm_read_byte(this->data_start_ + pos) << 24);
const uint8_t gray = pgm_read_byte(this->data_start_ + pos);
return Color(gray | gray << 8 | gray << 16 | gray << 24);
}
int Image::get_width() const { return this->width_; }
int Image::get_height() const { return this->height_; }
ImageType Image::get_type() const { return this->type_; }
Image::Image(const uint8_t *data_start, int width, int height)
: width_(width), height_(height), data_start_(data_start) {}
Image::Image(const uint8_t *data_start, int width, int height, int type)
: width_(width), height_(height), type_((ImageType) type), data_start_(data_start) {}
Image::Image(const uint8_t *data_start, int width, int height, ImageType type)
: width_(width), height_(height), type_(type), data_start_(data_start) {}
bool Animation::get_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return false;
const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
const uint32_t frame_index = this->height_ * width_8 * this->current_frame_;
if (frame_index >= this->width_ * this->height_ * this->animation_frame_count_)
return false;
const uint32_t pos = x + y * width_8 + frame_index;
return pgm_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u));
}
Color Animation::get_color_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return 0;
const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
if (frame_index >= this->width_ * this->height_ * this->animation_frame_count_)
return 0;
const uint32_t pos = (x + y * this->width_ + frame_index) * 3;
const uint32_t color32 = (pgm_read_byte(this->data_start_ + pos + 2) << 0) |
(pgm_read_byte(this->data_start_ + pos + 1) << 8) |
(pgm_read_byte(this->data_start_ + pos + 0) << 16);
return Color(color32);
}
Color Animation::get_grayscale_pixel(int x, int y) const {
if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
return 0;
const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
if (frame_index >= this->width_ * this->height_ * this->animation_frame_count_)
return 0;
const uint32_t pos = (x + y * this->width_ + frame_index);
const uint8_t gray = pgm_read_byte(this->data_start_ + pos);
return Color(gray | gray << 8 | gray << 16 | gray << 24);
}
Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type)
: Image(data_start, width, height, type), animation_frame_count_(animation_frame_count) {
current_frame_ = 0;
}
int Animation::get_animation_frame_count() const { return this->animation_frame_count_; }
int Animation::get_current_frame() const { return this->current_frame_; }
void Animation::next_frame() {
this->current_frame_++;
if (this->current_frame_ >= animation_frame_count_) {
this->current_frame_ = 0;
}
}
DisplayPage::DisplayPage(const display_writer_t &writer) : writer_(writer) {}
void DisplayPage::show() { this->parent_->show_page(this); }

View File

@@ -68,7 +68,7 @@ extern const Color COLOR_OFF;
/// Turn the pixel ON.
extern const Color COLOR_ON;
enum ImageType { BINARY = 0, GRAYSCALE = 1, RGB = 2 };
enum ImageType { IMAGE_TYPE_BINARY = 0, IMAGE_TYPE_GRAYSCALE = 1, IMAGE_TYPE_RGB24 = 2 };
enum DisplayRotation {
DISPLAY_ROTATION_0_DEGREES = 0,
@@ -262,9 +262,15 @@ class DisplayBuffer {
__attribute__((format(strftime, 5, 0)));
#endif
/// Draw the `image` with the top-left corner at [x,y] to the screen.
void image(int x, int y, Image *image);
void image(int x, int y, Color color, Image *image, bool invert = false);
/** Draw the `image` with the top-left corner at [x,y] to the screen.
*
* @param x The x coordinate of the upper left corner.
* @param y The y coordinate of the upper left corner.
* @param image The image to draw
* @param color_on The color to replace in binary images for the on bits.
* @param color_off The color to replace in binary images for the off bits.
*/
void image(int x, int y, Image *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
/** Get the text bounds of the given string.
*
@@ -381,11 +387,10 @@ class Font {
class Image {
public:
Image(const uint8_t *data_start, int width, int height);
Image(const uint8_t *data_start, int width, int height, int type);
bool get_pixel(int x, int y) const;
Color get_color_pixel(int x, int y) const;
Color get_grayscale_pixel(int x, int y) const;
Image(const uint8_t *data_start, int width, int height, ImageType type);
virtual bool get_pixel(int x, int y) const;
virtual Color get_color_pixel(int x, int y) const;
virtual Color get_grayscale_pixel(int x, int y) const;
int get_width() const;
int get_height() const;
ImageType get_type() const;
@@ -393,10 +398,26 @@ class Image {
protected:
int width_;
int height_;
ImageType type_{BINARY};
ImageType type_;
const uint8_t *data_start_;
};
class Animation : public Image {
public:
Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type);
bool get_pixel(int x, int y) const override;
Color get_color_pixel(int x, int y) const override;
Color get_grayscale_pixel(int x, int y) const override;
int get_animation_frame_count() const;
int get_current_frame() const;
void next_frame();
protected:
int current_frame_;
int animation_frame_count_;
};
template<typename... Ts> class DisplayPageShowAction : public Action<Ts...> {
public:
TEMPLATABLE_VALUE(DisplayPage *, page)

View File

View File

@@ -0,0 +1,105 @@
#include "ds1307.h"
#include "esphome/core/log.h"
// Datasheet:
// - https://datasheets.maximintegrated.com/en/ds/DS1307.pdf
namespace esphome {
namespace ds1307 {
static const char *TAG = "ds1307";
void DS1307Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up DS1307...");
if (!this->read_rtc_()) {
this->mark_failed();
}
}
void DS1307Component::update() { this->read_time(); }
void DS1307Component::dump_config() {
ESP_LOGCONFIG(TAG, "DS1307:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, "Communication with DS1307 failed!");
}
ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str());
}
float DS1307Component::get_setup_priority() const { return setup_priority::DATA; }
void DS1307Component::read_time() {
if (!this->read_rtc_()) {
return;
}
if (ds1307_.reg.ch) {
ESP_LOGW(TAG, "RTC halted, not syncing to system clock.");
return;
}
time::ESPTime rtc_time{.second = uint8_t(ds1307_.reg.second + 10 * ds1307_.reg.second_10),
.minute = uint8_t(ds1307_.reg.minute + 10u * ds1307_.reg.minute_10),
.hour = uint8_t(ds1307_.reg.hour + 10u * ds1307_.reg.hour_10),
.day_of_week = uint8_t(ds1307_.reg.weekday),
.day_of_month = uint8_t(ds1307_.reg.day + 10u * ds1307_.reg.day_10),
.day_of_year = 1, // ignored by recalc_timestamp_utc(false)
.month = uint8_t(ds1307_.reg.month + 10u * ds1307_.reg.month_10),
.year = uint16_t(ds1307_.reg.year + 10u * ds1307_.reg.year_10 + 2000)};
rtc_time.recalc_timestamp_utc(false);
if (!rtc_time.is_valid()) {
ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock.");
return;
}
time::RealTimeClock::synchronize_epoch_(rtc_time.timestamp);
}
void DS1307Component::write_time() {
auto now = time::RealTimeClock::utcnow();
if (!now.is_valid()) {
ESP_LOGE(TAG, "Invalid system time, not syncing to RTC.");
return;
}
ds1307_.reg.year = (now.year - 2000) % 10;
ds1307_.reg.year_10 = (now.year - 2000) / 10 % 10;
ds1307_.reg.month = now.month % 10;
ds1307_.reg.month_10 = now.month / 10;
ds1307_.reg.day = now.day_of_month % 10;
ds1307_.reg.day_10 = now.day_of_month / 10;
ds1307_.reg.weekday = now.day_of_week;
ds1307_.reg.hour = now.hour % 10;
ds1307_.reg.hour_10 = now.hour / 10;
ds1307_.reg.minute = now.minute % 10;
ds1307_.reg.minute_10 = now.minute / 10;
ds1307_.reg.second = now.second % 10;
ds1307_.reg.second_10 = now.second / 10;
ds1307_.reg.ch = false;
this->write_rtc_();
}
bool DS1307Component::read_rtc_() {
if (!this->read_bytes(0, this->ds1307_.raw, sizeof(this->ds1307_.raw))) {
ESP_LOGE(TAG, "Can't read I2C data.");
return false;
}
ESP_LOGD(TAG, "Read %0u%0u:%0u%0u:%0u%0u 20%0u%0u-%0u%0u-%0u%0u CH:%s RS:%0u SQWE:%s OUT:%s", ds1307_.reg.hour_10,
ds1307_.reg.hour, ds1307_.reg.minute_10, ds1307_.reg.minute, ds1307_.reg.second_10, ds1307_.reg.second,
ds1307_.reg.year_10, ds1307_.reg.year, ds1307_.reg.month_10, ds1307_.reg.month, ds1307_.reg.day_10,
ds1307_.reg.day, ONOFF(ds1307_.reg.ch), ds1307_.reg.rs, ONOFF(ds1307_.reg.sqwe), ONOFF(ds1307_.reg.out));
return true;
}
bool DS1307Component::write_rtc_() {
if (!this->write_bytes(0, this->ds1307_.raw, sizeof(this->ds1307_.raw))) {
ESP_LOGE(TAG, "Can't write I2C data.");
return false;
}
ESP_LOGD(TAG, "Write %0u%0u:%0u%0u:%0u%0u 20%0u%0u-%0u%0u-%0u%0u CH:%s RS:%0u SQWE:%s OUT:%s", ds1307_.reg.hour_10,
ds1307_.reg.hour, ds1307_.reg.minute_10, ds1307_.reg.minute, ds1307_.reg.second_10, ds1307_.reg.second,
ds1307_.reg.year_10, ds1307_.reg.year, ds1307_.reg.month_10, ds1307_.reg.month, ds1307_.reg.day_10,
ds1307_.reg.day, ONOFF(ds1307_.reg.ch), ds1307_.reg.rs, ONOFF(ds1307_.reg.sqwe), ONOFF(ds1307_.reg.out));
return true;
}
} // namespace ds1307
} // namespace esphome

View File

@@ -0,0 +1,70 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/time/real_time_clock.h"
namespace esphome {
namespace ds1307 {
class DS1307Component : public time::RealTimeClock, public i2c::I2CDevice {
public:
void setup() override;
void update() override;
void dump_config() override;
float get_setup_priority() const override;
void read_time();
void write_time();
protected:
bool read_rtc_();
bool write_rtc_();
union DS1307Reg {
struct {
uint8_t second : 4;
uint8_t second_10 : 3;
bool ch : 1;
uint8_t minute : 4;
uint8_t minute_10 : 3;
uint8_t unused_1 : 1;
uint8_t hour : 4;
uint8_t hour_10 : 2;
uint8_t unused_2 : 2;
uint8_t weekday : 3;
uint8_t unused_3 : 5;
uint8_t day : 4;
uint8_t day_10 : 2;
uint8_t unused_4 : 2;
uint8_t month : 4;
uint8_t month_10 : 1;
uint8_t unused_5 : 3;
uint8_t year : 4;
uint8_t year_10 : 4;
uint8_t rs : 2;
uint8_t unused_6 : 2;
bool sqwe : 1;
uint8_t unused_7 : 2;
bool out : 1;
} reg;
mutable uint8_t raw[sizeof(reg)];
} ds1307_;
};
template<typename... Ts> class WriteAction : public Action<Ts...>, public Parented<DS1307Component> {
public:
void play(Ts... x) override { this->parent_->write_time(); }
};
template<typename... Ts> class ReadAction : public Action<Ts...>, public Parented<DS1307Component> {
public:
void play(Ts... x) override { this->parent_->read_time(); }
};
} // namespace ds1307
} // namespace esphome

View File

@@ -0,0 +1,44 @@
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome import automation
from esphome.components import i2c, time
from esphome.const import CONF_ID
CODEOWNERS = ['@badbadc0ffee']
DEPENDENCIES = ['i2c']
ds1307_ns = cg.esphome_ns.namespace('ds1307')
DS1307Component = ds1307_ns.class_('DS1307Component', time.RealTimeClock, i2c.I2CDevice)
WriteAction = ds1307_ns.class_('WriteAction', automation.Action)
ReadAction = ds1307_ns.class_('ReadAction', automation.Action)
CONFIG_SCHEMA = time.TIME_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(DS1307Component),
}).extend(i2c.i2c_device_schema(0x68))
@automation.register_action('ds1307.write_time', WriteAction, cv.Schema({
cv.GenerateID(): cv.use_id(DS1307Component),
}))
def ds1307_write_time_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
yield cg.register_parented(var, config[CONF_ID])
yield var
@automation.register_action('ds1307.read_time', ReadAction, automation.maybe_simple_id({
cv.GenerateID(): cv.use_id(DS1307Component),
}))
def ds1307_read_time_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
yield cg.register_parented(var, config[CONF_ID])
yield var
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
yield time.register_time(var, config)

View File

@@ -2,7 +2,8 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.const import CONF_FREQUENCY, CONF_ID, CONF_NAME, CONF_PIN, CONF_SCL, CONF_SDA, \
ESP_PLATFORM_ESP32, CONF_DATA_PINS, CONF_RESET_PIN, CONF_RESOLUTION, CONF_BRIGHTNESS
ESP_PLATFORM_ESP32, CONF_DATA_PINS, CONF_RESET_PIN, CONF_RESOLUTION, CONF_BRIGHTNESS, \
CONF_CONTRAST
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
DEPENDENCIES = ['api']
@@ -47,7 +48,6 @@ CONF_IDLE_FRAMERATE = 'idle_framerate'
CONF_JPEG_QUALITY = 'jpeg_quality'
CONF_VERTICAL_FLIP = 'vertical_flip'
CONF_HORIZONTAL_MIRROR = 'horizontal_mirror'
CONF_CONTRAST = 'contrast'
CONF_SATURATION = 'saturation'
CONF_TEST_PATTERN = 'test_pattern'

View File

View File

@@ -0,0 +1,86 @@
#include "ezo.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ezo {
static const char *TAG = "ezo.sensor";
static const uint16_t EZO_STATE_WAIT = 1;
static const uint16_t EZO_STATE_SEND_TEMP = 2;
static const uint16_t EZO_STATE_WAIT_TEMP = 4;
void EZOSensor::dump_config() {
LOG_SENSOR("", "EZO", this);
LOG_I2C_DEVICE(this);
if (this->is_failed())
ESP_LOGE(TAG, "Communication with EZO circuit failed!");
LOG_UPDATE_INTERVAL(this);
}
void EZOSensor::update() {
if (this->state_ & EZO_STATE_WAIT) {
ESP_LOGE(TAG, "update overrun, still waiting for previous response");
return;
}
uint8_t c = 'R';
this->write_bytes_raw(&c, 1);
this->state_ |= EZO_STATE_WAIT;
this->start_time_ = millis();
this->wait_time_ = 900;
}
void EZOSensor::loop() {
uint8_t buf[20];
if (!(this->state_ & EZO_STATE_WAIT)) {
if (this->state_ & EZO_STATE_SEND_TEMP) {
int len = sprintf((char *) buf, "T,%0.3f", this->tempcomp_);
this->write_bytes_raw(buf, len);
this->state_ = EZO_STATE_WAIT | EZO_STATE_WAIT_TEMP;
this->start_time_ = millis();
this->wait_time_ = 300;
}
return;
}
if (millis() - this->start_time_ < this->wait_time_)
return;
buf[0] = 0;
if (!this->read_bytes_raw(buf, 20)) {
ESP_LOGE(TAG, "read error");
this->state_ = 0;
return;
}
switch (buf[0]) {
case 1:
break;
case 2:
ESP_LOGE(TAG, "device returned a syntax error");
break;
case 254:
return; // keep waiting
case 255:
ESP_LOGE(TAG, "device returned no data");
break;
default:
ESP_LOGE(TAG, "device returned an unknown response: %d", buf[0]);
break;
}
if (this->state_ & EZO_STATE_WAIT_TEMP) {
this->state_ = 0;
return;
}
this->state_ &= ~EZO_STATE_WAIT;
if (buf[0] != 1)
return;
float val = strtof((char *) &buf[1], nullptr);
this->publish_state(val);
}
void EZOSensor::set_tempcomp_value(float temp) {
this->tempcomp_ = temp;
this->state_ |= EZO_STATE_SEND_TEMP;
}
} // namespace ezo
} // namespace esphome

View File

@@ -0,0 +1,28 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace ezo {
/// This class implements support for the EZO circuits in i2c mode
class EZOSensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
public:
void loop() override;
void dump_config() override;
void update() override;
float get_setup_priority() const override { return setup_priority::DATA; };
void set_tempcomp_value(float temp);
protected:
unsigned long start_time_ = 0;
unsigned long wait_time_ = 0;
uint16_t state_ = 0;
float tempcomp_;
};
} // namespace ezo
} // namespace esphome

View File

@@ -0,0 +1,23 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_ID
CODEOWNERS = ['@ssieb']
DEPENDENCIES = ['i2c']
ezo_ns = cg.esphome_ns.namespace('ezo')
EZOSensor = ezo_ns.class_('EZOSensor', sensor.Sensor, cg.PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(EZOSensor),
}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(None))
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield sensor.register_sensor(var, config)
yield i2c.register_i2c_device(var, config)

View File

@@ -38,7 +38,7 @@ class FastLEDLightOutput : public light::AddressableLight {
return *this->controller_;
}
template<ESPIChipsets CHIPSET, uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER, uint8_t SPI_DATA_RATE>
template<ESPIChipsets CHIPSET, uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER, uint32_t SPI_DATA_RATE>
CLEDController &add_leds(int num_leds) {
switch (CHIPSET) {
case LPD8806: {

View File

@@ -2,7 +2,8 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import fastled_base
from esphome.const import CONF_CHIPSET, CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_NUM_LEDS, CONF_RGB_ORDER
from esphome.const import CONF_CHIPSET, CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_DATA_RATE, \
CONF_NUM_LEDS, CONF_RGB_ORDER
AUTO_LOAD = ['fastled_base']
@@ -21,15 +22,24 @@ CONFIG_SCHEMA = fastled_base.BASE_SCHEMA.extend({
cv.Required(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
cv.Required(CONF_DATA_PIN): pins.output_pin,
cv.Required(CONF_CLOCK_PIN): pins.output_pin,
cv.Optional(CONF_DATA_RATE): cv.frequency,
})
def to_code(config):
var = yield fastled_base.new_fastled_light(config)
rgb_order = None
if CONF_RGB_ORDER in config:
rgb_order = cg.RawExpression(config[CONF_RGB_ORDER])
rgb_order = cg.RawExpression(config[CONF_RGB_ORDER] if CONF_RGB_ORDER in config else "RGB")
data_rate = None
if CONF_DATA_RATE in config:
data_rate_khz = int(config[CONF_DATA_RATE] / 1000)
if data_rate_khz < 1000:
data_rate = cg.RawExpression(f"DATA_RATE_KHZ({data_rate_khz})")
else:
data_rate_mhz = int(data_rate_khz / 1000)
data_rate = cg.RawExpression(f"DATA_RATE_MHZ({data_rate_mhz})")
template_args = cg.TemplateArguments(cg.RawExpression(config[CONF_CHIPSET]),
config[CONF_DATA_PIN], config[CONF_CLOCK_PIN], rgb_order)
config[CONF_DATA_PIN], config[CONF_CLOCK_PIN], rgb_order,
data_rate)
cg.add(var.add_leds(template_args, config[CONF_NUM_LEDS]))

View File

@@ -42,9 +42,9 @@ def validate_glyphs(value):
def validate_pillow_installed(value):
try:
import PIL
except ImportError:
except ImportError as err:
raise cv.Invalid("Please install the pillow python package to use this feature. "
"(pip install pillow)")
"(pip install pillow)") from err
if PIL.__version__[0] < '4':
raise cv.Invalid("Please update your pillow installation to at least 4.0.x. "

View File

@@ -36,7 +36,10 @@ const uint8_t FUJITSU_GENERAL_FAN_HIGH_BYTE10 = 0x01;
const uint8_t FUJITSU_GENERAL_FAN_MEDIUM_BYTE10 = 0x02;
const uint8_t FUJITSU_GENERAL_FAN_LOW_BYTE10 = 0x03;
const uint8_t FUJITSU_GENERAL_FAN_SILENT_BYTE10 = 0x04;
const uint8_t FUJITSU_GENERAL_SWING_MASK_BYTE10 = 0b00010000;
const uint8_t FUJITSU_GENERAL_SWING_NONE_BYTE10 = 0x00;
const uint8_t FUJITSU_GENERAL_SWING_VERTICAL_BYTE10 = 0x01;
const uint8_t FUJITSU_GENERAL_SWING_HORIZONTAL_BYTE10 = 0x02;
const uint8_t FUJITSU_GENERAL_SWING_BOTH_BYTE10 = 0x03;
const uint8_t FUJITSU_GENERAL_BASE_BYTE10 = 0x00;
const uint8_t FUJITSU_GENERAL_BASE_BYTE11 = 0x00;
@@ -74,7 +77,12 @@ const uint16_t FUJITSU_GENERAL_TRL_SPACE = 8000;
const uint32_t FUJITSU_GENERAL_CARRIER_FREQUENCY = 38000;
FujitsuGeneralClimate::FujitsuGeneralClimate() : ClimateIR(FUJITSU_GENERAL_TEMP_MIN, FUJITSU_GENERAL_TEMP_MAX, 1) {}
FujitsuGeneralClimate::FujitsuGeneralClimate()
: ClimateIR(
FUJITSU_GENERAL_TEMP_MIN, FUJITSU_GENERAL_TEMP_MAX, 1.0f, true, true,
{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH},
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, climate::CLIMATE_SWING_HORIZONTAL,
climate::CLIMATE_SWING_BOTH}) {}
void FujitsuGeneralClimate::transmit_state() {
if (this->mode == climate::CLIMATE_MODE_OFF) {
@@ -101,8 +109,8 @@ void FujitsuGeneralClimate::transmit_state() {
remote_state[15] = FUJITSU_GENERAL_BASE_BYTE15;
// Set temperature
uint8_t safecelsius = std::max((uint8_t) this->target_temperature, FUJITSU_GENERAL_TEMP_MIN);
safecelsius = std::min(safecelsius, FUJITSU_GENERAL_TEMP_MAX);
auto safecelsius =
(uint8_t) roundf(clamp(this->target_temperature, FUJITSU_GENERAL_TEMP_MIN, FUJITSU_GENERAL_TEMP_MAX));
remote_state[8] = (byte) safecelsius - 16;
remote_state[8] = remote_state[8] << 4;
@@ -119,18 +127,52 @@ void FujitsuGeneralClimate::transmit_state() {
case climate::CLIMATE_MODE_HEAT:
remote_state[9] = FUJITSU_GENERAL_MODE_HEAT_BYTE9;
break;
case climate::CLIMATE_MODE_DRY:
remote_state[9] = FUJITSU_GENERAL_MODE_DRY_BYTE9;
break;
case climate::CLIMATE_MODE_FAN_ONLY:
remote_state[9] = FUJITSU_GENERAL_MODE_FAN_BYTE9;
break;
case climate::CLIMATE_MODE_AUTO:
default:
remote_state[9] = FUJITSU_GENERAL_MODE_AUTO_BYTE9;
break;
// TODO: CLIMATE_MODE_FAN_ONLY, CLIMATE_MODE_DRY, CLIMATE_MODE_10C are missing in esphome
// TODO: CLIMATE_MODE_10C are missing in esphome
}
// TODO: missing support for fan speed
remote_state[10] = FUJITSU_GENERAL_FAN_AUTO_BYTE10;
// Set fan
switch (this->fan_mode) {
case climate::CLIMATE_FAN_HIGH:
remote_state[10] = FUJITSU_GENERAL_FAN_HIGH_BYTE10;
break;
case climate::CLIMATE_FAN_MEDIUM:
remote_state[10] = FUJITSU_GENERAL_FAN_MEDIUM_BYTE10;
break;
case climate::CLIMATE_FAN_LOW:
remote_state[10] = FUJITSU_GENERAL_FAN_LOW_BYTE10;
break;
case climate::CLIMATE_FAN_AUTO:
default:
remote_state[10] = FUJITSU_GENERAL_FAN_AUTO_BYTE10;
break;
}
// TODO: missing support for swing
// remote_state[10] = (byte) remote_state[10] | FUJITSU_GENERAL_SWING_MASK_BYTE10;
// Set swing
switch (this->swing_mode) {
case climate::CLIMATE_SWING_VERTICAL:
remote_state[10] = (byte) remote_state[10] | (FUJITSU_GENERAL_SWING_VERTICAL_BYTE10 << 4);
break;
case climate::CLIMATE_SWING_HORIZONTAL:
remote_state[10] = (byte) remote_state[10] | (FUJITSU_GENERAL_SWING_HORIZONTAL_BYTE10 << 4);
break;
case climate::CLIMATE_SWING_BOTH:
remote_state[10] = (byte) remote_state[10] | (FUJITSU_GENERAL_SWING_BOTH_BYTE10 << 4);
break;
case climate::CLIMATE_SWING_OFF:
default:
remote_state[10] = (byte) remote_state[10] | (FUJITSU_GENERAL_SWING_NONE_BYTE10 << 4);
break;
}
// TODO: missing support for outdoor unit low noise
// remote_state[14] = (byte) remote_state[14] | FUJITSU_GENERAL_OUTDOOR_UNIT_LOW_NOISE_BYTE14;

View File

@@ -6,12 +6,12 @@ from .. import gps_ns, GPSListener, CONF_GPS_ID, GPS
DEPENDENCIES = ['gps']
GPSTime = gps_ns.class_('GPSTime', time_.RealTimeClock, GPSListener)
GPSTime = gps_ns.class_('GPSTime', cg.PollingComponent, time_.RealTimeClock, GPSListener)
CONFIG_SCHEMA = time_.TIME_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(GPSTime),
cv.GenerateID(CONF_GPS_ID): cv.use_id(GPS),
}).extend(cv.COMPONENT_SCHEMA)
}).extend(cv.polling_component_schema('5min'))
def to_code(config):

View File

@@ -9,13 +9,11 @@ namespace gps {
class GPSTime : public time::RealTimeClock, public GPSListener {
public:
void update() override { this->from_tiny_gps_(this->get_tiny_gps()); };
void on_update(TinyGPSPlus &tiny_gps) override {
if (!this->has_time_)
this->from_tiny_gps_(tiny_gps);
}
void setup() override {
this->set_interval(5 * 60 * 1000, [this]() { this->from_tiny_gps_(this->get_tiny_gps()); });
}
protected:
void from_tiny_gps_(TinyGPSPlus &tiny_gps);

View File

View File

@@ -0,0 +1,76 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/output/float_output.h"
#include "esphome/components/light/light_output.h"
#include "esphome/core/log.h"
namespace esphome {
namespace hbridge {
// Using PollingComponent as the updates are more consistent and reduces flickering
class HBridgeLightOutput : public PollingComponent, public light::LightOutput {
public:
HBridgeLightOutput() : PollingComponent(1) {}
void set_pina_pin(output::FloatOutput *pina_pin) { pina_pin_ = pina_pin; }
void set_pinb_pin(output::FloatOutput *pinb_pin) { pinb_pin_ = pinb_pin; }
light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supports_brightness(true); // Dimming
traits.set_supports_rgb(false);
traits.set_supports_rgb_white_value(true); // hbridge color
traits.set_supports_color_temperature(false);
return traits;
}
void setup() override { this->forward_direction_ = false; }
void update() override {
// This method runs around 60 times per second
// We cannot do the PWM ourselves so we are reliant on the hardware PWM
if (!this->forward_direction_) { // First LED Direction
this->pinb_pin_->set_level(this->duty_off_);
this->pina_pin_->set_level(this->pina_duty_);
this->forward_direction_ = true;
} else { // Second LED Direction
this->pina_pin_->set_level(this->duty_off_);
this->pinb_pin_->set_level(this->pinb_duty_);
this->forward_direction_ = false;
}
}
float get_setup_priority() const override { return setup_priority::HARDWARE; }
void write_state(light::LightState *state) override {
float bright;
state->current_values_as_brightness(&bright);
state->set_gamma_correct(0);
float red, green, blue, white;
state->current_values_as_rgbw(&red, &green, &blue, &white);
if ((white / bright) > 0.55) {
this->pina_duty_ = (bright * (1 - (white / bright)));
this->pinb_duty_ = bright;
} else if (white < 0.45) {
this->pina_duty_ = bright;
this->pinb_duty_ = white;
} else {
this->pina_duty_ = bright;
this->pinb_duty_ = bright;
}
}
protected:
output::FloatOutput *pina_pin_;
output::FloatOutput *pinb_pin_;
float pina_duty_ = 0;
float pinb_duty_ = 0;
float duty_off_ = 0;
bool forward_direction_ = false;
};
} // namespace hbridge
} // namespace esphome

View File

@@ -0,0 +1,24 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import light, output
from esphome.const import CONF_OUTPUT_ID, CONF_PIN_A, CONF_PIN_B
hbridge_ns = cg.esphome_ns.namespace('hbridge')
HBridgeLightOutput = hbridge_ns.class_('HBridgeLightOutput', cg.PollingComponent, light.LightOutput)
CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend({
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(HBridgeLightOutput),
cv.Required(CONF_PIN_A): cv.use_id(output.FloatOutput),
cv.Required(CONF_PIN_B): cv.use_id(output.FloatOutput),
})
def to_code(config):
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
yield cg.register_component(var, config)
yield light.register_light(var, config)
hside = yield cg.get_variable(config[CONF_PIN_A])
cg.add(var.set_pina_pin(hside))
lside = yield cg.get_variable(config[CONF_PIN_B])
cg.add(var.set_pinb_pin(lside))

View File

@@ -0,0 +1,18 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import climate_ir
from esphome.const import CONF_ID
AUTO_LOAD = ['climate_ir']
hitachi_ac344_ns = cg.esphome_ns.namespace('hitachi_ac344')
HitachiClimate = hitachi_ac344_ns.class_('HitachiClimate', climate_ir.ClimateIR)
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(HitachiClimate),
})
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield climate_ir.register_climate_ir(var, config)

View File

@@ -0,0 +1,365 @@
#include "hitachi_ac344.h"
namespace esphome {
namespace hitachi_ac344 {
static const char *TAG = "climate.hitachi_ac344";
void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, const uint8_t data) {
if (offset >= 8 || !nbits)
return; // Short circuit as it won't change.
// Calculate the mask for the supplied value.
uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits));
// Calculate the mask & clear the space for the data.
// Clear the destination bits.
*dst &= ~(uint8_t)(mask << offset);
// Merge in the data.
*dst |= ((data & mask) << offset);
}
void set_bit(uint8_t *const data, const uint8_t position, const bool on) {
uint8_t mask = 1 << position;
if (on)
*data |= mask;
else
*data &= ~mask;
}
uint8_t *invert_byte_pairs(uint8_t *ptr, const uint16_t length) {
for (uint16_t i = 1; i < length; i += 2) {
// Code done this way to avoid a compiler warning bug.
uint8_t inv = ~*(ptr + i - 1);
*(ptr + i) = inv;
}
return ptr;
}
bool HitachiClimate::get_power_() { return remote_state_[HITACHI_AC344_POWER_BYTE] == HITACHI_AC344_POWER_ON; }
void HitachiClimate::set_power_(bool on) {
set_button_(HITACHI_AC344_BUTTON_POWER);
remote_state_[HITACHI_AC344_POWER_BYTE] = on ? HITACHI_AC344_POWER_ON : HITACHI_AC344_POWER_OFF;
}
uint8_t HitachiClimate::get_mode_() { return remote_state_[HITACHI_AC344_MODE_BYTE] & 0xF; }
void HitachiClimate::set_mode_(uint8_t mode) {
uint8_t new_mode = mode;
switch (mode) {
// Fan mode sets a special temp.
case HITACHI_AC344_MODE_FAN:
set_temp_(HITACHI_AC344_TEMP_FAN, false);
break;
case HITACHI_AC344_MODE_HEAT:
case HITACHI_AC344_MODE_COOL:
case HITACHI_AC344_MODE_DRY:
break;
default:
new_mode = HITACHI_AC344_MODE_COOL;
}
set_bits(&remote_state_[HITACHI_AC344_MODE_BYTE], 0, 4, new_mode);
if (new_mode != HITACHI_AC344_MODE_FAN)
set_temp_(previous_temp_);
set_fan_(get_fan_()); // Reset the fan speed after the mode change.
set_power_(true);
}
void HitachiClimate::set_temp_(uint8_t celsius, bool set_previous) {
uint8_t temp;
temp = std::min(celsius, HITACHI_AC344_TEMP_MAX);
temp = std::max(temp, HITACHI_AC344_TEMP_MIN);
set_bits(&remote_state_[HITACHI_AC344_TEMP_BYTE], HITACHI_AC344_TEMP_OFFSET, HITACHI_AC344_TEMP_SIZE, temp);
if (previous_temp_ > temp)
set_button_(HITACHI_AC344_BUTTON_TEMP_DOWN);
else if (previous_temp_ < temp)
set_button_(HITACHI_AC344_BUTTON_TEMP_UP);
if (set_previous)
previous_temp_ = temp;
}
uint8_t HitachiClimate::get_fan_() { return remote_state_[HITACHI_AC344_FAN_BYTE] >> 4 & 0xF; }
void HitachiClimate::set_fan_(uint8_t speed) {
uint8_t new_speed = std::max(speed, HITACHI_AC344_FAN_MIN);
uint8_t fan_max = HITACHI_AC344_FAN_MAX;
// Only 2 x low speeds in Dry mode or Auto
if (get_mode_() == HITACHI_AC344_MODE_DRY && speed == HITACHI_AC344_FAN_AUTO) {
fan_max = HITACHI_AC344_FAN_AUTO;
} else if (get_mode_() == HITACHI_AC344_MODE_DRY) {
fan_max = HITACHI_AC344_FAN_MAX_DRY;
} else if (get_mode_() == HITACHI_AC344_MODE_FAN && speed == HITACHI_AC344_FAN_AUTO) {
// Fan Mode does not have auto. Set to safe low
new_speed = HITACHI_AC344_FAN_MIN;
}
new_speed = std::min(new_speed, fan_max);
// Handle the setting the button value if we are going to change the value.
if (new_speed != get_fan_())
set_button_(HITACHI_AC344_BUTTON_FAN);
// Set the values
set_bits(&remote_state_[HITACHI_AC344_FAN_BYTE], 4, 4, new_speed);
remote_state_[9] = 0x92;
// When fan is at min/max, additional bytes seem to be set
if (new_speed == HITACHI_AC344_FAN_MIN)
remote_state_[9] = 0x98;
remote_state_[29] = 0x01;
}
void HitachiClimate::set_swing_v_toggle_(bool on) {
uint8_t button = get_button_(); // Get the current button value.
if (on)
button = HITACHI_AC344_BUTTON_SWINGV; // Set the button to SwingV.
else if (button == HITACHI_AC344_BUTTON_SWINGV) // Asked to unset it
// It was set previous, so use Power as a default
button = HITACHI_AC344_BUTTON_POWER;
set_button_(button);
}
bool HitachiClimate::get_swing_v_toggle_() { return get_button_() == HITACHI_AC344_BUTTON_SWINGV; }
void HitachiClimate::set_swing_v_(bool on) {
set_swing_v_toggle_(on); // Set the button value.
set_bit(&remote_state_[HITACHI_AC344_SWINGV_BYTE], HITACHI_AC344_SWINGV_OFFSET, on);
}
bool HitachiClimate::get_swing_v_() {
return GETBIT8(remote_state_[HITACHI_AC344_SWINGV_BYTE], HITACHI_AC344_SWINGV_OFFSET);
}
void HitachiClimate::set_swing_h_(uint8_t position) {
if (position > HITACHI_AC344_SWINGH_LEFT_MAX)
return set_swing_h_(HITACHI_AC344_SWINGH_MIDDLE);
set_bits(&remote_state_[HITACHI_AC344_SWINGH_BYTE], HITACHI_AC344_SWINGH_OFFSET, HITACHI_AC344_SWINGH_SIZE, position);
set_button_(HITACHI_AC344_BUTTON_SWINGH);
}
uint8_t HitachiClimate::get_swing_h_() {
return GETBITS8(remote_state_[HITACHI_AC344_SWINGH_BYTE], HITACHI_AC344_SWINGH_OFFSET, HITACHI_AC344_SWINGH_SIZE);
}
uint8_t HitachiClimate::get_button_() { return remote_state_[HITACHI_AC344_BUTTON_BYTE]; }
void HitachiClimate::set_button_(uint8_t button) { remote_state_[HITACHI_AC344_BUTTON_BYTE] = button; }
void HitachiClimate::transmit_state() {
switch (this->mode) {
case climate::CLIMATE_MODE_COOL:
set_mode_(HITACHI_AC344_MODE_COOL);
break;
case climate::CLIMATE_MODE_DRY:
set_mode_(HITACHI_AC344_MODE_DRY);
break;
case climate::CLIMATE_MODE_HEAT:
set_mode_(HITACHI_AC344_MODE_HEAT);
break;
case climate::CLIMATE_MODE_AUTO:
set_mode_(HITACHI_AC344_MODE_AUTO);
break;
case climate::CLIMATE_MODE_FAN_ONLY:
set_mode_(HITACHI_AC344_MODE_FAN);
break;
case climate::CLIMATE_MODE_OFF:
set_power_(false);
break;
}
set_temp_(static_cast<uint8_t>(this->target_temperature));
switch (this->fan_mode) {
case climate::CLIMATE_FAN_LOW:
set_fan_(HITACHI_AC344_FAN_LOW);
break;
case climate::CLIMATE_FAN_MEDIUM:
set_fan_(HITACHI_AC344_FAN_MEDIUM);
break;
case climate::CLIMATE_FAN_HIGH:
set_fan_(HITACHI_AC344_FAN_HIGH);
break;
case climate::CLIMATE_FAN_ON:
case climate::CLIMATE_FAN_AUTO:
default:
set_fan_(HITACHI_AC344_FAN_AUTO);
}
switch (this->swing_mode) {
case climate::CLIMATE_SWING_BOTH:
set_swing_v_(true);
set_swing_h_(HITACHI_AC344_SWINGH_AUTO);
break;
case climate::CLIMATE_SWING_VERTICAL:
set_swing_v_(true);
set_swing_h_(HITACHI_AC344_SWINGH_MIDDLE);
break;
case climate::CLIMATE_SWING_HORIZONTAL:
set_swing_v_(false);
set_swing_h_(HITACHI_AC344_SWINGH_AUTO);
break;
case climate::CLIMATE_SWING_OFF:
set_swing_v_(false);
set_swing_h_(HITACHI_AC344_SWINGH_MIDDLE);
break;
}
// TODO: find change value to set button, now always set to power button
set_button_(HITACHI_AC344_BUTTON_POWER);
invert_byte_pairs(remote_state_ + 3, HITACHI_AC344_STATE_LENGTH - 3);
auto transmit = this->transmitter_->transmit();
auto data = transmit.get_data();
data->set_carrier_frequency(HITACHI_AC344_FREQ);
uint8_t repeat = 0;
for (uint8_t r = 0; r <= repeat; r++) {
// Header
data->item(HITACHI_AC344_HDR_MARK, HITACHI_AC344_HDR_SPACE);
// Data
for (uint8_t i : remote_state_) {
for (uint8_t j = 0; j < 8; j++) {
data->mark(HITACHI_AC344_BIT_MARK);
bool bit = i & (1 << j);
data->space(bit ? HITACHI_AC344_ONE_SPACE : HITACHI_AC344_ZERO_SPACE);
}
}
// Footer
data->item(HITACHI_AC344_BIT_MARK, HITACHI_AC344_MIN_GAP);
}
transmit.perform();
dump_state_("Sent", remote_state_);
}
bool HitachiClimate::parse_mode_(const uint8_t remote_state[]) {
uint8_t power = remote_state[HITACHI_AC344_POWER_BYTE];
ESP_LOGV(TAG, "Power: %02X %02X", remote_state[HITACHI_AC344_POWER_BYTE], power);
uint8_t mode = remote_state[HITACHI_AC344_MODE_BYTE] & 0xF;
ESP_LOGV(TAG, "Mode: %02X %02X", remote_state[HITACHI_AC344_MODE_BYTE], mode);
if (power == HITACHI_AC344_POWER_ON) {
switch (mode) {
case HITACHI_AC344_MODE_COOL:
this->mode = climate::CLIMATE_MODE_COOL;
break;
case HITACHI_AC344_MODE_DRY:
this->mode = climate::CLIMATE_MODE_DRY;
break;
case HITACHI_AC344_MODE_HEAT:
this->mode = climate::CLIMATE_MODE_HEAT;
break;
case HITACHI_AC344_MODE_AUTO:
this->mode = climate::CLIMATE_MODE_AUTO;
break;
case HITACHI_AC344_MODE_FAN:
this->mode = climate::CLIMATE_MODE_FAN_ONLY;
break;
}
} else {
this->mode = climate::CLIMATE_MODE_OFF;
}
return true;
}
bool HitachiClimate::parse_temperature_(const uint8_t remote_state[]) {
uint8_t temperature =
GETBITS8(remote_state[HITACHI_AC344_TEMP_BYTE], HITACHI_AC344_TEMP_OFFSET, HITACHI_AC344_TEMP_SIZE);
this->target_temperature = temperature;
ESP_LOGV(TAG, "Temperature: %02X %02u %04f", remote_state[HITACHI_AC344_TEMP_BYTE], temperature,
this->target_temperature);
return true;
}
bool HitachiClimate::parse_fan_(const uint8_t remote_state[]) {
uint8_t fan_mode = remote_state[HITACHI_AC344_FAN_BYTE] >> 4 & 0xF;
ESP_LOGV(TAG, "Fan: %02X %02X", remote_state[HITACHI_AC344_FAN_BYTE], fan_mode);
switch (fan_mode) {
case HITACHI_AC344_FAN_MIN:
case HITACHI_AC344_FAN_LOW:
this->fan_mode = climate::CLIMATE_FAN_LOW;
break;
case HITACHI_AC344_FAN_MEDIUM:
this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
break;
case HITACHI_AC344_FAN_HIGH:
case HITACHI_AC344_FAN_MAX:
this->fan_mode = climate::CLIMATE_FAN_HIGH;
break;
case HITACHI_AC344_FAN_AUTO:
this->fan_mode = climate::CLIMATE_FAN_AUTO;
break;
}
return true;
}
bool HitachiClimate::parse_swing_(const uint8_t remote_state[]) {
uint8_t swing_modeh =
GETBITS8(remote_state[HITACHI_AC344_SWINGH_BYTE], HITACHI_AC344_SWINGH_OFFSET, HITACHI_AC344_SWINGH_SIZE);
ESP_LOGV(TAG, "SwingH: %02X %02X", remote_state[HITACHI_AC344_SWINGH_BYTE], swing_modeh);
if ((swing_modeh & 0x7) == 0x0) {
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
} else if ((swing_modeh & 0x3) == 0x3) {
this->swing_mode = climate::CLIMATE_SWING_OFF;
} else {
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
}
return true;
}
bool HitachiClimate::on_receive(remote_base::RemoteReceiveData data) {
// Validate header
if (!data.expect_item(HITACHI_AC344_HDR_MARK, HITACHI_AC344_HDR_SPACE)) {
ESP_LOGVV(TAG, "Header fail");
return false;
}
uint8_t recv_state[HITACHI_AC344_STATE_LENGTH] = {0};
// Read all bytes.
for (uint8_t pos = 0; pos < HITACHI_AC344_STATE_LENGTH; pos++) {
// Read bit
for (int8_t bit = 0; bit < 8; bit++) {
if (data.expect_item(HITACHI_AC344_BIT_MARK, HITACHI_AC344_ONE_SPACE))
recv_state[pos] |= 1 << bit;
else if (!data.expect_item(HITACHI_AC344_BIT_MARK, HITACHI_AC344_ZERO_SPACE)) {
ESP_LOGVV(TAG, "Byte %d bit %d fail", pos, bit);
return false;
}
}
}
// Validate footer
if (!data.expect_mark(HITACHI_AC344_BIT_MARK)) {
ESP_LOGVV(TAG, "Footer fail");
return false;
}
dump_state_("Recv", recv_state);
// parse mode
this->parse_mode_(recv_state);
// parse temperature
this->parse_temperature_(recv_state);
// parse fan
this->parse_fan_(recv_state);
// parse swingv
this->parse_swing_(recv_state);
this->publish_state();
for (uint8_t i = 0; i < HITACHI_AC344_STATE_LENGTH; i++)
remote_state_[i] = recv_state[i];
return true;
}
void HitachiClimate::dump_state_(const char action[], uint8_t state[]) {
for (uint16_t i = 0; i < HITACHI_AC344_STATE_LENGTH - 10; i += 10) {
ESP_LOGV(TAG, "%s: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", action, state[i + 0], state[i + 1],
state[i + 2], state[i + 3], state[i + 4], state[i + 5], state[i + 6], state[i + 7], state[i + 8],
state[i + 9]);
}
ESP_LOGV(TAG, "%s: %02X %02X %02X", action, state[40], state[41], state[42]);
}
} // namespace hitachi_ac344
} // namespace esphome

View File

@@ -0,0 +1,122 @@
#pragma once
#include "esphome/core/log.h"
#include "esphome/components/climate_ir/climate_ir.h"
namespace esphome {
namespace hitachi_ac344 {
const uint16_t HITACHI_AC344_HDR_MARK = 3300; // ac
const uint16_t HITACHI_AC344_HDR_SPACE = 1700; // ac
const uint16_t HITACHI_AC344_BIT_MARK = 400;
const uint16_t HITACHI_AC344_ONE_SPACE = 1250;
const uint16_t HITACHI_AC344_ZERO_SPACE = 500;
const uint32_t HITACHI_AC344_MIN_GAP = 100000; // just a guess.
const uint16_t HITACHI_AC344_FREQ = 38000; // Hz.
const uint8_t HITACHI_AC344_BUTTON_BYTE = 11;
const uint8_t HITACHI_AC344_BUTTON_POWER = 0x13;
const uint8_t HITACHI_AC344_BUTTON_SLEEP = 0x31;
const uint8_t HITACHI_AC344_BUTTON_MODE = 0x41;
const uint8_t HITACHI_AC344_BUTTON_FAN = 0x42;
const uint8_t HITACHI_AC344_BUTTON_TEMP_DOWN = 0x43;
const uint8_t HITACHI_AC344_BUTTON_TEMP_UP = 0x44;
const uint8_t HITACHI_AC344_BUTTON_SWINGV = 0x81;
const uint8_t HITACHI_AC344_BUTTON_SWINGH = 0x8C;
const uint8_t HITACHI_AC344_BUTTON_MILDEWPROOF = 0xE2;
const uint8_t HITACHI_AC344_TEMP_BYTE = 13;
const uint8_t HITACHI_AC344_TEMP_OFFSET = 2;
const uint8_t HITACHI_AC344_TEMP_SIZE = 6;
const uint8_t HITACHI_AC344_TEMP_MIN = 16; // 16C
const uint8_t HITACHI_AC344_TEMP_MAX = 32; // 32C
const uint8_t HITACHI_AC344_TEMP_FAN = 27; // 27C
const uint8_t HITACHI_AC344_TIMER_BYTE = 15;
const uint8_t HITACHI_AC344_MODE_BYTE = 25;
const uint8_t HITACHI_AC344_MODE_FAN = 1;
const uint8_t HITACHI_AC344_MODE_COOL = 3;
const uint8_t HITACHI_AC344_MODE_DRY = 5;
const uint8_t HITACHI_AC344_MODE_HEAT = 6;
const uint8_t HITACHI_AC344_MODE_AUTO = 7;
const uint8_t HITACHI_AC344_FAN_BYTE = HITACHI_AC344_MODE_BYTE;
const uint8_t HITACHI_AC344_FAN_MIN = 1;
const uint8_t HITACHI_AC344_FAN_LOW = 2;
const uint8_t HITACHI_AC344_FAN_MEDIUM = 3;
const uint8_t HITACHI_AC344_FAN_HIGH = 4;
const uint8_t HITACHI_AC344_FAN_AUTO = 5;
const uint8_t HITACHI_AC344_FAN_MAX = 6;
const uint8_t HITACHI_AC344_FAN_MAX_DRY = 2;
const uint8_t HITACHI_AC344_POWER_BYTE = 27;
const uint8_t HITACHI_AC344_POWER_ON = 0xF1;
const uint8_t HITACHI_AC344_POWER_OFF = 0xE1;
const uint8_t HITACHI_AC344_SWINGH_BYTE = 35;
const uint8_t HITACHI_AC344_SWINGH_OFFSET = 0; // Mask 0b00000xxx
const uint8_t HITACHI_AC344_SWINGH_SIZE = 3; // Mask 0b00000xxx
const uint8_t HITACHI_AC344_SWINGH_AUTO = 0; // 0b000
const uint8_t HITACHI_AC344_SWINGH_RIGHT_MAX = 1; // 0b001
const uint8_t HITACHI_AC344_SWINGH_RIGHT = 2; // 0b010
const uint8_t HITACHI_AC344_SWINGH_MIDDLE = 3; // 0b011
const uint8_t HITACHI_AC344_SWINGH_LEFT = 4; // 0b100
const uint8_t HITACHI_AC344_SWINGH_LEFT_MAX = 5; // 0b101
const uint8_t HITACHI_AC344_SWINGV_BYTE = 37;
const uint8_t HITACHI_AC344_SWINGV_OFFSET = 5; // Mask 0b00x00000
const uint8_t HITACHI_AC344_MILDEWPROOF_BYTE = HITACHI_AC344_SWINGV_BYTE;
const uint8_t HITACHI_AC344_MILDEWPROOF_OFFSET = 2; // Mask 0b00000x00
const uint16_t HITACHI_AC344_STATE_LENGTH = 43;
const uint16_t HITACHI_AC344_BITS = HITACHI_AC344_STATE_LENGTH * 8;
#define GETBIT8(a, b) (a & ((uint8_t) 1 << b))
#define GETBITS8(data, offset, size) (((data) & (((uint8_t) UINT8_MAX >> (8 - (size))) << (offset))) >> (offset))
class HitachiClimate : public climate_ir::ClimateIR {
public:
HitachiClimate()
: climate_ir::ClimateIR(
HITACHI_AC344_TEMP_MIN, HITACHI_AC344_TEMP_MAX, 1.0F, true, true,
std::vector<climate::ClimateFanMode>{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW,
climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH},
std::vector<climate::ClimateSwingMode>{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_HORIZONTAL}) {}
protected:
uint8_t remote_state_[HITACHI_AC344_STATE_LENGTH]{0x01, 0x10, 0x00, 0x40, 0x00, 0xFF, 0x00, 0xCC, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t previous_temp_{27};
// Transmit via IR the state of this climate controller.
void transmit_state() override;
bool get_power_();
void set_power_(bool on);
uint8_t get_mode_();
void set_mode_(uint8_t mode);
void set_temp_(uint8_t celsius, bool set_previous = false);
uint8_t get_fan_();
void set_fan_(uint8_t speed);
void set_swing_v_toggle_(bool on);
bool get_swing_v_toggle_();
void set_swing_v_(bool on);
bool get_swing_v_();
void set_swing_h_(uint8_t position);
uint8_t get_swing_h_();
uint8_t get_button_();
void set_button_(uint8_t button);
// Handle received IR Buffer
bool on_receive(remote_base::RemoteReceiveData data) override;
bool parse_mode_(const uint8_t remote_state[]);
bool parse_temperature_(const uint8_t remote_state[]);
bool parse_fan_(const uint8_t remote_state[]);
bool parse_swing_(const uint8_t remote_state[]);
bool parse_state_frame_(const uint8_t frame[]);
void dump_state_(const char action[], uint8_t remote_state[]);
};
} // namespace hitachi_ac344
} // namespace esphome

View File

@@ -79,6 +79,12 @@ void HLW8012Component::update() {
this->power_sensor_->publish_state(power);
}
if (this->energy_sensor_ != nullptr) {
cf_total_pulses_ += raw_cf;
float energy = cf_total_pulses_ * power_multiplier_micros / 3600 / 1000000.0f;
this->energy_sensor_->publish_state(energy);
}
if (this->change_mode_at_++ == this->change_mode_every_) {
this->current_mode_ = !this->current_mode_;
ESP_LOGV(TAG, "Changing mode to %s mode", this->current_mode_ ? "CURRENT" : "VOLTAGE");

View File

@@ -29,6 +29,7 @@ class HLW8012Component : public PollingComponent {
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
protected:
uint32_t nth_value_{0};
@@ -37,6 +38,7 @@ class HLW8012Component : public PollingComponent {
uint32_t change_mode_every_{8};
float current_resistor_{0.001};
float voltage_divider_{2351};
uint64_t cf_total_pulses_{0};
GPIOPin *sel_pin_;
GPIOPin *cf_pin_;
pulse_counter::PulseCounterStorage cf_store_;
@@ -45,6 +47,7 @@ class HLW8012Component : public PollingComponent {
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
sensor::Sensor *energy_sensor_{nullptr};
};
} // namespace hlw8012

View File

@@ -3,8 +3,8 @@ import esphome.config_validation as cv
from esphome import pins
from esphome.components import sensor
from esphome.const import CONF_CHANGE_MODE_EVERY, CONF_INITIAL_MODE, CONF_CURRENT, \
CONF_CURRENT_RESISTOR, CONF_ID, CONF_POWER, CONF_SEL_PIN, CONF_VOLTAGE, CONF_VOLTAGE_DIVIDER, \
ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT
CONF_CURRENT_RESISTOR, CONF_ID, CONF_POWER, CONF_ENERGY, CONF_SEL_PIN, CONF_VOLTAGE, \
CONF_VOLTAGE_DIVIDER, ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, UNIT_WATT_HOURS
AUTO_LOAD = ['pulse_counter']
@@ -29,6 +29,7 @@ CONFIG_SCHEMA = cv.Schema({
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 1),
cv.Optional(CONF_CURRENT): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2),
cv.Optional(CONF_POWER): sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 1),
cv.Optional(CONF_ENERGY): sensor.sensor_schema(UNIT_WATT_HOURS, ICON_FLASH, 1),
cv.Optional(CONF_CURRENT_RESISTOR, default=0.001): cv.resistance,
cv.Optional(CONF_VOLTAGE_DIVIDER, default=2351): cv.positive_float,
@@ -57,6 +58,9 @@ def to_code(config):
if CONF_POWER in config:
sens = yield sensor.new_sensor(config[CONF_POWER])
cg.add(var.set_power_sensor(sens))
if CONF_ENERGY in config:
sens = yield sensor.new_sensor(config[CONF_ENERGY])
cg.add(var.set_energy_sensor(sens))
cg.add(var.set_current_resistor(config[CONF_CURRENT_RESISTOR]))
cg.add(var.set_voltage_divider(config[CONF_VOLTAGE_DIVIDER]))
cg.add(var.set_change_mode_every(config[CONF_CHANGE_MODE_EVERY]))

View File

@@ -17,7 +17,7 @@ class AQICalculator : public AbstractAQICalculator {
int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 51}, {51, 100}, {101, 150}, {151, 200}, {201, 300}, {301, 500}};
int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 12}, {13, 45}, {36, 55}, {56, 150}, {151, 250}, {251, 500}};
int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 12}, {13, 35}, {36, 55}, {56, 150}, {151, 250}, {251, 500}};
int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254},
{255, 354}, {355, 424}, {425, 604}};
@@ -33,7 +33,7 @@ class AQICalculator : public AbstractAQICalculator {
}
int get_grid_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
for (int i = 0; i < AMOUNT_OF_LEVELS - 1; i++) {
for (int i = 0; i < AMOUNT_OF_LEVELS; i++) {
if (value >= array[i][0] && value <= array[i][1]) {
return i;
}

View File

@@ -10,17 +10,13 @@ void HomeassistantTime::dump_config() {
ESP_LOGCONFIG(TAG, "Home Assistant Time:");
ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str());
}
float HomeassistantTime::get_setup_priority() const { return setup_priority::DATA; }
void HomeassistantTime::setup() {
global_homeassistant_time = this;
this->set_interval(15 * 60 * 1000, []() {
// re-request time every 15 minutes
api::global_api_server->request_time();
});
}
float HomeassistantTime::get_setup_priority() const { return setup_priority::DATA; }
void HomeassistantTime::setup() { global_homeassistant_time = this; }
void HomeassistantTime::update() { api::global_api_server->request_time(); }
HomeassistantTime *global_homeassistant_time = nullptr;
} // namespace homeassistant
} // namespace esphome

View File

@@ -10,6 +10,7 @@ namespace homeassistant {
class HomeassistantTime : public time::RealTimeClock {
public:
void setup() override;
void update() override;
void dump_config() override;
void set_epoch_time(uint32_t epoch) { this->synchronize_epoch_(epoch); }
float get_setup_priority() const override;

View File

@@ -43,8 +43,8 @@ def validate_url(value):
value = cv.string(value)
try:
parsed = list(urlparse.urlparse(value))
except Exception:
raise cv.Invalid('Invalid URL')
except Exception as err:
raise cv.Invalid('Invalid URL') from err
if not parsed[0] or not parsed[1]:
raise cv.Invalid('URL must have a URL scheme and host')

View File

@@ -12,9 +12,20 @@ void HttpRequestComponent::dump_config() {
ESP_LOGCONFIG(TAG, " User-Agent: %s", this->useragent_);
}
void HttpRequestComponent::set_url(std::string url) {
this->url_ = url;
this->secure_ = url.compare(0, 6, "https:") == 0;
if (!this->last_url_.empty() && this->url_ != this->last_url_) {
// Close connection if url has been changed
this->client_.setReuse(false);
this->client_.end();
}
this->client_.setReuse(true);
}
void HttpRequestComponent::send() {
bool begin_status = false;
this->client_.setReuse(true);
const String url = this->url_.c_str();
#ifdef ARDUINO_ARCH_ESP32
begin_status = this->client_.begin(url);
@@ -78,7 +89,10 @@ WiFiClient *HttpRequestComponent::get_wifi_client_() {
}
#endif
void HttpRequestComponent::close() { this->client_.end(); }
void HttpRequestComponent::close() {
this->last_url_ = this->url_;
this->client_.end();
}
const char *HttpRequestComponent::get_string() {
static const String STR = this->client_.getString();

View File

@@ -27,10 +27,7 @@ class HttpRequestComponent : public Component {
void dump_config() override;
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void set_url(std::string url) {
this->url_ = url;
this->secure_ = url.compare(0, 6, "https:") == 0;
}
void set_url(std::string url);
void set_method(const char *method) { this->method_ = method; }
void set_useragent(const char *useragent) { this->useragent_ = useragent; }
void set_timeout(uint16_t timeout) { this->timeout_ = timeout; }
@@ -43,6 +40,7 @@ class HttpRequestComponent : public Component {
protected:
HTTPClient client_{};
std::string url_;
std::string last_url_;
const char *method_;
const char *useragent_{nullptr};
bool secure_;

View File

@@ -56,8 +56,8 @@ void I2CComponent::raw_begin_transmission(uint8_t address) {
ESP_LOGVV(TAG, "Beginning Transmission to 0x%02X:", address);
this->wire_->beginTransmission(address);
}
bool I2CComponent::raw_end_transmission(uint8_t address) {
uint8_t status = this->wire_->endTransmission();
bool I2CComponent::raw_end_transmission(uint8_t address, bool send_stop) {
uint8_t status = this->wire_->endTransmission(send_stop);
ESP_LOGVV(TAG, " Transmission ended. Status code: 0x%02X", status);
switch (status) {

View File

@@ -94,7 +94,7 @@ class I2CComponent : public Component {
void raw_begin_transmission(uint8_t address);
/// End a write transmission to an address, return true if successful.
bool raw_end_transmission(uint8_t address);
bool raw_end_transmission(uint8_t address, bool send_stop = true);
/** Request data from an address with a number of (8-bit) bytes.
*
@@ -173,6 +173,17 @@ class I2CDevice {
I2CRegister reg(uint8_t a_register) { return {this, a_register}; }
/// Begin a write transmission.
void raw_begin_transmission() { this->parent_->raw_begin_transmission(this->address_); };
/// End a write transmission, return true if successful.
bool raw_end_transmission(bool send_stop = true) {
return this->parent_->raw_end_transmission(this->address_, send_stop);
};
/// Write len amount of bytes from data. begin_transmission_ must be called before this.
void raw_write(const uint8_t *data, uint8_t len) { this->parent_->raw_write(this->address_, data, len); };
/** Read len amount of bytes from a register into data. Optionally with a conversion time after
* writing the register value to the bus.
*

View File

View File

@@ -0,0 +1,61 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import display, spi
from esphome.const import CONF_DC_PIN, \
CONF_ID, CONF_LAMBDA, CONF_MODEL, CONF_PAGES, CONF_RESET_PIN
DEPENDENCIES = ['spi']
CONF_LED_PIN = 'led_pin'
ili9341_ns = cg.esphome_ns.namespace('ili9341')
ili9341 = ili9341_ns.class_('ILI9341Display', cg.PollingComponent, spi.SPIDevice,
display.DisplayBuffer)
ILI9341M5Stack = ili9341_ns.class_('ILI9341M5Stack', ili9341)
ILI9341TFT24 = ili9341_ns.class_('ILI9341TFT24', ili9341)
ILI9341Model = ili9341_ns.enum('ILI9341Model')
MODELS = {
'M5STACK': ILI9341Model.M5STACK,
'TFT_2.4': ILI9341Model.TFT_24,
}
ILI9341_MODEL = cv.enum(MODELS, upper=True, space="_")
CONFIG_SCHEMA = cv.All(display.FULL_DISPLAY_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(ili9341),
cv.Required(CONF_MODEL): ILI9341_MODEL,
cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_LED_PIN): pins.gpio_output_pin_schema,
}).extend(cv.polling_component_schema('1s')).extend(spi.spi_device_schema()),
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA))
def to_code(config):
if config[CONF_MODEL] == 'M5STACK':
lcd_type = ILI9341M5Stack
if config[CONF_MODEL] == 'TFT_2.4':
lcd_type = ILI9341TFT24
rhs = lcd_type.new()
var = cg.Pvariable(config[CONF_ID], rhs)
yield cg.register_component(var, config)
yield display.register_display(var, config)
yield spi.register_spi_device(var, config)
cg.add(var.set_model(config[CONF_MODEL]))
dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN])
cg.add(var.set_dc_pin(dc))
if CONF_LAMBDA in config:
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [(display.DisplayBufferRef, 'it')],
return_type=cg.void)
cg.add(var.set_writer(lambda_))
if CONF_RESET_PIN in config:
reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN])
cg.add(var.set_reset_pin(reset))
if CONF_LED_PIN in config:
led_pin = yield cg.gpio_pin_expression(config[CONF_LED_PIN])
cg.add(var.set_led_pin(led_pin))

View File

@@ -0,0 +1,83 @@
#pragma once
namespace esphome {
namespace ili9341 {
// Color definitions
// clang-format off
static const uint8_t MADCTL_MY = 0x80; ///< Bit 7 Bottom to top
static const uint8_t MADCTL_MX = 0x40; ///< Bit 6 Right to left
static const uint8_t MADCTL_MV = 0x20; ///< Bit 5 Reverse Mode
static const uint8_t MADCTL_ML = 0x10; ///< Bit 4 LCD refresh Bottom to top
static const uint8_t MADCTL_RGB = 0x00; ///< Bit 3 Red-Green-Blue pixel order
static const uint8_t MADCTL_BGR = 0x08; ///< Bit 3 Blue-Green-Red pixel order
static const uint8_t MADCTL_MH = 0x04; ///< Bit 2 LCD refresh right to left
// clang-format on
static const uint16_t ILI9341_TFTWIDTH = 320; ///< ILI9341 max TFT width
static const uint16_t ILI9341_TFTHEIGHT = 240; ///< ILI9341 max TFT height
// All ILI9341 specific commands some are used by init()
static const uint8_t ILI9341_NOP = 0x00;
static const uint8_t ILI9341_SWRESET = 0x01;
static const uint8_t ILI9341_RDDID = 0x04;
static const uint8_t ILI9341_RDDST = 0x09;
static const uint8_t ILI9341_SLPIN = 0x10;
static const uint8_t ILI9341_SLPOUT = 0x11;
static const uint8_t ILI9341_PTLON = 0x12;
static const uint8_t ILI9341_NORON = 0x13;
static const uint8_t ILI9341_RDMODE = 0x0A;
static const uint8_t ILI9341_RDMADCTL = 0x0B;
static const uint8_t ILI9341_RDPIXFMT = 0x0C;
static const uint8_t ILI9341_RDIMGFMT = 0x0A;
static const uint8_t ILI9341_RDSELFDIAG = 0x0F;
static const uint8_t ILI9341_INVOFF = 0x20;
static const uint8_t ILI9341_INVON = 0x21;
static const uint8_t ILI9341_GAMMASET = 0x26;
static const uint8_t ILI9341_DISPOFF = 0x28;
static const uint8_t ILI9341_DISPON = 0x29;
static const uint8_t ILI9341_CASET = 0x2A;
static const uint8_t ILI9341_PASET = 0x2B;
static const uint8_t ILI9341_RAMWR = 0x2C;
static const uint8_t ILI9341_RAMRD = 0x2E;
static const uint8_t ILI9341_PTLAR = 0x30;
static const uint8_t ILI9341_VSCRDEF = 0x33;
static const uint8_t ILI9341_MADCTL = 0x36;
static const uint8_t ILI9341_VSCRSADD = 0x37;
static const uint8_t ILI9341_PIXFMT = 0x3A;
static const uint8_t ILI9341_WRDISBV = 0x51;
static const uint8_t ILI9341_RDDISBV = 0x52;
static const uint8_t ILI9341_WRCTRLD = 0x53;
static const uint8_t ILI9341_FRMCTR1 = 0xB1;
static const uint8_t ILI9341_FRMCTR2 = 0xB2;
static const uint8_t ILI9341_FRMCTR3 = 0xB3;
static const uint8_t ILI9341_INVCTR = 0xB4;
static const uint8_t ILI9341_DFUNCTR = 0xB6;
static const uint8_t ILI9341_PWCTR1 = 0xC0;
static const uint8_t ILI9341_PWCTR2 = 0xC1;
static const uint8_t ILI9341_PWCTR3 = 0xC2;
static const uint8_t ILI9341_PWCTR4 = 0xC3;
static const uint8_t ILI9341_PWCTR5 = 0xC4;
static const uint8_t ILI9341_VMCTR1 = 0xC5;
static const uint8_t ILI9341_VMCTR2 = 0xC7;
static const uint8_t ILI9341_RDID4 = 0xD3;
static const uint8_t ILI9341_RDINDEX = 0xD9;
static const uint8_t ILI9341_RDID1 = 0xDA;
static const uint8_t ILI9341_RDID2 = 0xDB;
static const uint8_t ILI9341_RDID3 = 0xDC;
static const uint8_t ILI9341_RDIDX = 0xDD; // TBC
static const uint8_t ILI9341_GMCTRP1 = 0xE0;
static const uint8_t ILI9341_GMCTRN1 = 0xE1;
} // namespace ili9341
} // namespace esphome

View File

@@ -0,0 +1,240 @@
#include "ili9341_display.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace ili9341 {
static const char *TAG = "ili9341";
void ILI9341Display::setup_pins_() {
this->init_internal_(this->get_buffer_length_());
this->dc_pin_->setup(); // OUTPUT
this->dc_pin_->digital_write(false);
if (this->reset_pin_ != nullptr) {
this->reset_pin_->setup(); // OUTPUT
this->reset_pin_->digital_write(true);
}
if (this->led_pin_ != nullptr) {
this->led_pin_->setup();
this->led_pin_->digital_write(true);
}
this->spi_setup();
this->reset_();
}
void ILI9341Display::dump_config() {
LOG_DISPLAY("", "ili9341", this);
ESP_LOGCONFIG(TAG, " Width: %d, Height: %d, Rotation: %d", this->width_, this->height_, this->rotation_);
LOG_PIN(" Reset Pin: ", this->reset_pin_);
LOG_PIN(" DC Pin: ", this->dc_pin_);
LOG_PIN(" Busy Pin: ", this->busy_pin_);
LOG_PIN(" Backlight Pin: ", this->led_pin_);
LOG_UPDATE_INTERVAL(this);
}
float ILI9341Display::get_setup_priority() const { return setup_priority::PROCESSOR; }
void ILI9341Display::command(uint8_t value) {
this->start_command_();
this->write_byte(value);
this->end_command_();
}
void ILI9341Display::reset_() {
if (this->reset_pin_ != nullptr) {
this->reset_pin_->digital_write(false);
delay(10);
this->reset_pin_->digital_write(true);
delay(10);
}
}
void ILI9341Display::data(uint8_t value) {
this->start_data_();
this->write_byte(value);
this->end_data_();
}
void ILI9341Display::send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes) {
this->command(command_byte); // Send the command byte
this->start_data_();
this->write_array(data_bytes, num_data_bytes);
this->end_data_();
}
uint8_t ILI9341Display::read_command(uint8_t command_byte, uint8_t index) {
uint8_t data = 0x10 + index;
this->send_command(0xD9, &data, 1); // Set Index Register
uint8_t result;
this->start_command_();
this->write_byte(command_byte);
this->start_data_();
do {
result = this->read_byte();
} while (index--);
this->end_data_();
return result;
}
void ILI9341Display::update() {
this->do_update_();
this->display_();
}
void ILI9341Display::display_() {
// we will only update the changed window to the display
int w = this->x_high_ - this->x_low_ + 1;
int h = this->y_high_ - this->y_low_ + 1;
set_addr_window_(this->x_low_, this->y_low_, w, h);
this->start_data_();
uint32_t start_pos = ((this->y_low_ * this->width_) + x_low_);
for (uint16_t row = 0; row < h; row++) {
for (uint16_t col = 0; col < w; col++) {
uint32_t pos = start_pos + (row * width_) + col;
uint16_t color = convert_to_16bit_color_(buffer_[pos]);
this->write_byte(color >> 8);
this->write_byte(color);
}
}
this->end_data_();
// invalidate watermarks
this->x_low_ = this->width_;
this->y_low_ = this->height_;
this->x_high_ = 0;
this->y_high_ = 0;
}
uint16_t ILI9341Display::convert_to_16bit_color_(uint8_t color_8bit) {
int r = color_8bit >> 5;
int g = (color_8bit >> 2) & 0x07;
int b = color_8bit & 0x03;
uint16_t color = (r * 0x04) << 11;
color |= (g * 0x09) << 5;
color |= (b * 0x0A);
return color;
}
uint8_t ILI9341Display::convert_to_8bit_color_(uint16_t color_16bit) {
// convert 16bit color to 8 bit buffer
uint8_t r = color_16bit >> 11;
uint8_t g = (color_16bit >> 5) & 0x3F;
uint8_t b = color_16bit & 0x1F;
return ((b / 0x0A) | ((g / 0x09) << 2) | ((r / 0x04) << 5));
}
void ILI9341Display::fill(Color color) {
auto color565 = color.to_rgb_565();
memset(this->buffer_, convert_to_8bit_color_(color565), this->get_buffer_length_());
this->x_low_ = 0;
this->y_low_ = 0;
this->x_high_ = this->get_width_internal() - 1;
this->y_high_ = this->get_height_internal() - 1;
}
void ILI9341Display::fill_internal_(Color color) {
this->set_addr_window_(0, 0, this->get_width_internal(), this->get_height_internal());
this->start_data_();
auto color565 = color.to_rgb_565();
for (uint32_t i = 0; i < (this->get_width_internal()) * (this->get_height_internal()); i++) {
this->write_byte(color565 >> 8);
this->write_byte(color565);
buffer_[i] = 0;
}
this->end_data_();
}
void HOT ILI9341Display::draw_absolute_pixel_internal(int x, int y, Color color) {
if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0)
return;
// low and high watermark may speed up drawing from buffer
this->x_low_ = (x < this->x_low_) ? x : this->x_low_;
this->y_low_ = (y < this->y_low_) ? y : this->y_low_;
this->x_high_ = (x > this->x_high_) ? x : this->x_high_;
this->y_high_ = (y > this->y_high_) ? y : this->y_high_;
uint32_t pos = (y * width_) + x;
auto color565 = color.to_rgb_565();
buffer_[pos] = convert_to_8bit_color_(color565);
}
// should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color
// values per bit is huge
uint32_t ILI9341Display::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal(); }
void ILI9341Display::start_command_() {
this->dc_pin_->digital_write(false);
this->enable();
}
void ILI9341Display::end_command_() { this->disable(); }
void ILI9341Display::start_data_() {
this->dc_pin_->digital_write(true);
this->enable();
}
void ILI9341Display::end_data_() { this->disable(); }
void ILI9341Display::init_lcd_(const uint8_t *init_cmd) {
uint8_t cmd, x, num_args;
const uint8_t *addr = init_cmd;
while ((cmd = pgm_read_byte(addr++)) > 0) {
x = pgm_read_byte(addr++);
num_args = x & 0x7F;
send_command(cmd, addr, num_args);
addr += num_args;
if (x & 0x80)
delay(150); // NOLINT
}
}
void ILI9341Display::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) {
uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1);
this->command(ILI9341_CASET); // Column address set
this->start_data_();
this->write_byte(x1 >> 8);
this->write_byte(x1);
this->write_byte(x2 >> 8);
this->write_byte(x2);
this->end_data_();
this->command(ILI9341_PASET); // Row address set
this->start_data_();
this->write_byte(y1 >> 8);
this->write_byte(y1);
this->write_byte(y2 >> 8);
this->write_byte(y2);
this->end_data_();
this->command(ILI9341_RAMWR); // Write to RAM
}
void ILI9341Display::invert_display_(bool invert) { this->command(invert ? ILI9341_INVON : ILI9341_INVOFF); }
int ILI9341Display::get_width_internal() { return this->width_; }
int ILI9341Display::get_height_internal() { return this->height_; }
// M5Stack display
void ILI9341M5Stack::initialize() {
this->init_lcd_(INITCMD_M5STACK);
this->width_ = 320;
this->height_ = 240;
this->invert_display_(true);
this->fill_internal_(COLOR_BLACK);
}
// 24_TFT display
void ILI9341TFT24::initialize() {
this->init_lcd_(INITCMD_TFT);
this->width_ = 240;
this->height_ = 320;
this->fill_internal_(COLOR_BLACK);
}
} // namespace ili9341
} // namespace esphome

View File

@@ -0,0 +1,92 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/spi/spi.h"
#include "esphome/components/display/display_buffer.h"
#include "ili9341_defines.h"
#include "ili9341_init.h"
namespace esphome {
namespace ili9341 {
enum ILI9341Model {
M5STACK = 0,
TFT_24,
};
class ILI9341Display : public PollingComponent,
public display::DisplayBuffer,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_40MHZ> {
public:
void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; }
float get_setup_priority() const override;
void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; }
void set_led_pin(GPIOPin *led) { this->led_pin_ = led; }
void set_model(ILI9341Model model) { this->model_ = model; }
void command(uint8_t value);
void data(uint8_t value);
void send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes);
uint8_t read_command(uint8_t command_byte, uint8_t index);
virtual void initialize() = 0;
void update() override;
void fill(Color color) override;
void dump_config() override;
void setup() override {
this->setup_pins_();
this->initialize();
}
protected:
void draw_absolute_pixel_internal(int x, int y, Color color) override;
void setup_pins_();
void init_lcd_(const uint8_t *init_cmd);
void set_addr_window_(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
void invert_display_(bool invert);
void reset_();
void fill_internal_(Color color);
void display_();
uint16_t convert_to_16bit_color_(uint8_t color_8bit);
uint8_t convert_to_8bit_color_(uint16_t color_16bit);
ILI9341Model model_;
int16_t width_{320}; ///< Display width as modified by current rotation
int16_t height_{240}; ///< Display height as modified by current rotation
uint16_t x_low_{0};
uint16_t y_low_{0};
uint16_t x_high_{0};
uint16_t y_high_{0};
uint32_t get_buffer_length_();
int get_width_internal() override;
int get_height_internal() override;
void start_command_();
void end_command_();
void start_data_();
void end_data_();
GPIOPin *reset_pin_{nullptr};
GPIOPin *led_pin_{nullptr};
GPIOPin *dc_pin_;
GPIOPin *busy_pin_{nullptr};
};
//----------- M5Stack display --------------
class ILI9341M5Stack : public ILI9341Display {
public:
void initialize() override;
};
//----------- ILI9341_24_TFT display --------------
class ILI9341TFT24 : public ILI9341Display {
public:
void initialize() override;
};
} // namespace ili9341
} // namespace esphome

View File

@@ -0,0 +1,70 @@
#pragma once
#include "esphome/core/helpers.h"
namespace esphome {
namespace ili9341 {
// clang-format off
static const uint8_t PROGMEM INITCMD_M5STACK[] = {
0xEF, 3, 0x03, 0x80, 0x02,
0xCF, 3, 0x00, 0xC1, 0x30,
0xED, 4, 0x64, 0x03, 0x12, 0x81,
0xE8, 3, 0x85, 0x00, 0x78,
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
0xF7, 1, 0x20,
0xEA, 2, 0x00, 0x00,
ILI9341_PWCTR1 , 1, 0x23, // Power control VRH[5:0]
ILI9341_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0]
ILI9341_VMCTR1 , 2, 0x3e, 0x28, // VCM control
ILI9341_VMCTR2 , 1, 0x86, // VCM control2
ILI9341_MADCTL , 1, MADCTL_BGR, // Memory Access Control
ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero
ILI9341_PIXFMT , 1, 0x55,
ILI9341_FRMCTR1 , 2, 0x00, 0x13,
ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
0xF2, 1, 0x00, // 3Gamma Function Disable
ILI9341_GAMMASET , 1, 0x01, // Gamma curve selected
ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
0x0E, 0x09, 0x00,
ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
0x31, 0x36, 0x0F,
ILI9341_SLPOUT , 0x80, // Exit Sleep
ILI9341_DISPON , 0x80, // Display on
0x00 // End of list
};
static const uint8_t PROGMEM INITCMD_TFT[] = {
0xEF, 3, 0x03, 0x80, 0x02,
0xCF, 3, 0x00, 0xC1, 0x30,
0xED, 4, 0x64, 0x03, 0x12, 0x81,
0xE8, 3, 0x85, 0x00, 0x78,
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
0xF7, 1, 0x20,
0xEA, 2, 0x00, 0x00,
ILI9341_PWCTR1 , 1, 0x23, // Power control VRH[5:0]
ILI9341_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0]
ILI9341_VMCTR1 , 2, 0x3e, 0x28, // VCM control
ILI9341_VMCTR2 , 1, 0x86, // VCM control2
ILI9341_MADCTL , 1, 0x48, // Memory Access Control
ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero
ILI9341_PIXFMT , 1, 0x55,
ILI9341_FRMCTR1 , 2, 0x00, 0x18,
ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
0xF2, 1, 0x00, // 3Gamma Function Disable
ILI9341_GAMMASET , 1, 0x01, // Gamma curve selected
ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
0x0E, 0x09, 0x00,
ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
0x31, 0x36, 0x0F,
ILI9341_SLPOUT , 0x80, // Exit Sleep
ILI9341_DISPON , 0x80, // Display on
0x00 // End of list
};
// clang-format on
} // namespace ili9341
} // namespace esphome

View File

@@ -4,14 +4,20 @@ from esphome import core
from esphome.components import display, font
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_FILE, CONF_ID, CONF_RESIZE, CONF_TYPE
from esphome.const import CONF_FILE, CONF_ID, CONF_TYPE, CONF_RESIZE, CONF_DITHER
from esphome.core import CORE, HexInt
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['display']
MULTI_CONF = True
ImageType = {'binary': 0, 'grayscale': 1, 'rgb': 2}
ImageType = display.display_ns.enum('ImageType')
IMAGE_TYPE = {
'BINARY': ImageType.IMAGE_TYPE_BINARY,
'GRAYSCALE': ImageType.IMAGE_TYPE_GRAYSCALE,
'RGB24': ImageType.IMAGE_TYPE_RGB24,
}
Image_ = display.display_ns.class_('Image')
@@ -21,7 +27,8 @@ IMAGE_SCHEMA = cv.Schema({
cv.Required(CONF_ID): cv.declare_id(Image_),
cv.Required(CONF_FILE): cv.file_,
cv.Optional(CONF_RESIZE): cv.dimensions,
cv.Optional(CONF_TYPE): cv.string,
cv.Optional(CONF_TYPE, default='BINARY'): cv.enum(IMAGE_TYPE, upper=True),
cv.Optional(CONF_DITHER, default='NONE'): cv.one_of("NONE", "FLOYDSTEINBERG", upper=True),
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
})
@@ -37,44 +44,41 @@ def to_code(config):
except Exception as e:
raise core.EsphomeError(f"Could not load image file {path}: {e}")
width, height = image.size
if CONF_RESIZE in config:
image.thumbnail(config[CONF_RESIZE])
if CONF_TYPE in config:
if config[CONF_TYPE].startswith('GRAYSCALE'):
width, height = image.size
image = image.convert('L', dither=Image.NONE)
pixels = list(image.getdata())
data = [0 for _ in range(height * width)]
pos = 0
for pix in pixels:
data[pos] = pix
pos += 1
rhs = [HexInt(x) for x in data]
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['grayscale'])
elif config[CONF_TYPE].startswith('RGB'):
width, height = image.size
image = image.convert('RGB')
pixels = list(image.getdata())
data = [0 for _ in range(height * width * 3)]
pos = 0
for pix in pixels:
data[pos] = pix[0]
pos += 1
data[pos] = pix[1]
pos += 1
data[pos] = pix[2]
pos += 1
rhs = [HexInt(x) for x in data]
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height, ImageType['rgb'])
else:
image = image.convert('1', dither=Image.NONE)
width, height = image.size
else:
if width > 500 or height > 500:
_LOGGER.warning("The image you requested is very big. Please consider using"
" the resize parameter.")
dither = Image.NONE if config[CONF_DITHER] == 'NONE' else Image.FLOYDSTEINBERG
if config[CONF_TYPE] == 'GRAYSCALE':
image = image.convert('L', dither=dither)
pixels = list(image.getdata())
data = [0 for _ in range(height * width)]
pos = 0
for pix in pixels:
data[pos] = pix
pos += 1
elif config[CONF_TYPE] == 'RGB24':
image = image.convert('RGB')
pixels = list(image.getdata())
data = [0 for _ in range(height * width * 3)]
pos = 0
for pix in pixels:
data[pos] = pix[0]
pos += 1
data[pos] = pix[1]
pos += 1
data[pos] = pix[2]
pos += 1
elif config[CONF_TYPE] == 'BINARY':
image = image.convert('1', dither=dither)
width8 = ((width + 7) // 8) * 8
data = [0 for _ in range(height * width8 // 8)]
for y in range(height):
@@ -84,6 +88,7 @@ def to_code(config):
pos = x + y * width8
data[pos // 8] |= 0x80 >> (pos % 8)
rhs = [HexInt(x) for x in data]
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height)
rhs = [HexInt(x) for x in data]
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
cg.new_Pvariable(config[CONF_ID], prog_arr, width, height,
IMAGE_TYPE[config[CONF_TYPE]])

View File

@@ -0,0 +1 @@
CODEOWNERS = ['@jesserockz']

View File

@@ -0,0 +1,141 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import display, i2c
from esphome.const import CONF_FULL_UPDATE_EVERY, CONF_ID, CONF_LAMBDA, CONF_PAGES, \
CONF_WAKEUP_PIN, ESP_PLATFORM_ESP32
DEPENDENCIES = ['i2c']
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
CONF_DISPLAY_DATA_0_PIN = 'display_data_0_pin'
CONF_DISPLAY_DATA_1_PIN = 'display_data_1_pin'
CONF_DISPLAY_DATA_2_PIN = 'display_data_2_pin'
CONF_DISPLAY_DATA_3_PIN = 'display_data_3_pin'
CONF_DISPLAY_DATA_4_PIN = 'display_data_4_pin'
CONF_DISPLAY_DATA_5_PIN = 'display_data_5_pin'
CONF_DISPLAY_DATA_6_PIN = 'display_data_6_pin'
CONF_DISPLAY_DATA_7_PIN = 'display_data_7_pin'
CONF_CL_PIN = 'cl_pin'
CONF_CKV_PIN = 'ckv_pin'
CONF_GREYSCALE = 'greyscale'
CONF_GMOD_PIN = 'gmod_pin'
CONF_GPIO0_ENABLE_PIN = 'gpio0_enable_pin'
CONF_LE_PIN = 'le_pin'
CONF_OE_PIN = 'oe_pin'
CONF_PARTIAL_UPDATING = 'partial_updating'
CONF_POWERUP_PIN = 'powerup_pin'
CONF_SPH_PIN = 'sph_pin'
CONF_SPV_PIN = 'spv_pin'
CONF_VCOM_PIN = 'vcom_pin'
inkplate6_ns = cg.esphome_ns.namespace('inkplate6')
Inkplate6 = inkplate6_ns.class_('Inkplate6', cg.PollingComponent, i2c.I2CDevice,
display.DisplayBuffer)
CONFIG_SCHEMA = cv.All(display.FULL_DISPLAY_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(Inkplate6),
cv.Optional(CONF_GREYSCALE, default=False): cv.boolean,
cv.Optional(CONF_PARTIAL_UPDATING, default=True): cv.boolean,
cv.Optional(CONF_FULL_UPDATE_EVERY, default=10): cv.uint32_t,
# Control pins
cv.Required(CONF_CKV_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_GMOD_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_GPIO0_ENABLE_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_OE_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_POWERUP_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_SPH_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_SPV_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_VCOM_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_WAKEUP_PIN): pins.gpio_output_pin_schema,
cv.Optional(CONF_CL_PIN, default=0): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_LE_PIN, default=2): pins.internal_gpio_output_pin_schema,
# Data pins
cv.Optional(CONF_DISPLAY_DATA_0_PIN, default=4): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_DISPLAY_DATA_1_PIN, default=5): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_DISPLAY_DATA_2_PIN, default=18): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_DISPLAY_DATA_3_PIN, default=19): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_DISPLAY_DATA_4_PIN, default=23): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_DISPLAY_DATA_5_PIN, default=25): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_DISPLAY_DATA_6_PIN, default=26): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_DISPLAY_DATA_7_PIN, default=27): pins.internal_gpio_output_pin_schema,
}).extend(cv.polling_component_schema('5s').extend(i2c.i2c_device_schema(0x48))),
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA))
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield display.register_display(var, config)
yield i2c.register_i2c_device(var, config)
if CONF_LAMBDA in config:
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [(display.DisplayBufferRef, 'it')],
return_type=cg.void)
cg.add(var.set_writer(lambda_))
cg.add(var.set_greyscale(config[CONF_GREYSCALE]))
cg.add(var.set_partial_updating(config[CONF_PARTIAL_UPDATING]))
cg.add(var.set_full_update_every(config[CONF_FULL_UPDATE_EVERY]))
ckv = yield cg.gpio_pin_expression(config[CONF_CKV_PIN])
cg.add(var.set_ckv_pin(ckv))
gmod = yield cg.gpio_pin_expression(config[CONF_GMOD_PIN])
cg.add(var.set_gmod_pin(gmod))
gpio0_enable = yield cg.gpio_pin_expression(config[CONF_GPIO0_ENABLE_PIN])
cg.add(var.set_gpio0_enable_pin(gpio0_enable))
oe = yield cg.gpio_pin_expression(config[CONF_OE_PIN])
cg.add(var.set_oe_pin(oe))
powerup = yield cg.gpio_pin_expression(config[CONF_POWERUP_PIN])
cg.add(var.set_powerup_pin(powerup))
sph = yield cg.gpio_pin_expression(config[CONF_SPH_PIN])
cg.add(var.set_sph_pin(sph))
spv = yield cg.gpio_pin_expression(config[CONF_SPV_PIN])
cg.add(var.set_spv_pin(spv))
vcom = yield cg.gpio_pin_expression(config[CONF_VCOM_PIN])
cg.add(var.set_vcom_pin(vcom))
wakeup = yield cg.gpio_pin_expression(config[CONF_WAKEUP_PIN])
cg.add(var.set_wakeup_pin(wakeup))
cl = yield cg.gpio_pin_expression(config[CONF_CL_PIN])
cg.add(var.set_cl_pin(cl))
le = yield cg.gpio_pin_expression(config[CONF_LE_PIN])
cg.add(var.set_le_pin(le))
display_data_0 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_0_PIN])
cg.add(var.set_display_data_0_pin(display_data_0))
display_data_1 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_1_PIN])
cg.add(var.set_display_data_1_pin(display_data_1))
display_data_2 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_2_PIN])
cg.add(var.set_display_data_2_pin(display_data_2))
display_data_3 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_3_PIN])
cg.add(var.set_display_data_3_pin(display_data_3))
display_data_4 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_4_PIN])
cg.add(var.set_display_data_4_pin(display_data_4))
display_data_5 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_5_PIN])
cg.add(var.set_display_data_5_pin(display_data_5))
display_data_6 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_6_PIN])
cg.add(var.set_display_data_6_pin(display_data_6))
display_data_7 = yield cg.gpio_pin_expression(config[CONF_DISPLAY_DATA_7_PIN])
cg.add(var.set_display_data_7_pin(display_data_7))
cg.add_build_flag('-DBOARD_HAS_PSRAM')

View File

@@ -0,0 +1,630 @@
#include "inkplate.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace inkplate6 {
static const char *TAG = "inkplate";
void Inkplate6::setup() {
this->initialize_();
this->vcom_pin_->setup();
this->powerup_pin_->setup();
this->wakeup_pin_->setup();
this->gpio0_enable_pin_->setup();
this->gpio0_enable_pin_->digital_write(true);
this->cl_pin_->setup();
this->le_pin_->setup();
this->ckv_pin_->setup();
this->gmod_pin_->setup();
this->oe_pin_->setup();
this->sph_pin_->setup();
this->spv_pin_->setup();
this->display_data_0_pin_->setup();
this->display_data_1_pin_->setup();
this->display_data_2_pin_->setup();
this->display_data_3_pin_->setup();
this->display_data_4_pin_->setup();
this->display_data_5_pin_->setup();
this->display_data_6_pin_->setup();
this->display_data_7_pin_->setup();
this->clean();
this->display();
}
void Inkplate6::initialize_() {
uint32_t buffer_size = this->get_buffer_length_();
if (this->partial_buffer_ != nullptr) {
free(this->partial_buffer_); // NOLINT
}
if (this->partial_buffer_2_ != nullptr) {
free(this->partial_buffer_2_); // NOLINT
}
if (this->buffer_ != nullptr) {
free(this->buffer_); // NOLINT
}
this->buffer_ = (uint8_t *) ps_malloc(buffer_size);
if (this->buffer_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate buffer for display!");
this->mark_failed();
return;
}
if (!this->greyscale_) {
this->partial_buffer_ = (uint8_t *) ps_malloc(buffer_size);
if (this->partial_buffer_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate partial buffer for display!");
this->mark_failed();
return;
}
this->partial_buffer_2_ = (uint8_t *) ps_malloc(buffer_size * 2);
if (this->partial_buffer_2_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate partial buffer 2 for display!");
this->mark_failed();
return;
}
memset(this->partial_buffer_, 0, buffer_size);
memset(this->partial_buffer_2_, 0, buffer_size * 2);
}
memset(this->buffer_, 0, buffer_size);
}
float Inkplate6::get_setup_priority() const { return setup_priority::PROCESSOR; }
size_t Inkplate6::get_buffer_length_() {
if (this->greyscale_) {
return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 2u;
} else {
return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u;
}
}
void Inkplate6::update() {
this->do_update_();
if (this->full_update_every_ > 0 && this->partial_updates_ >= this->full_update_every_) {
this->block_partial_ = true;
}
this->display();
}
void HOT Inkplate6::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)
return;
if (this->greyscale_) {
int x1 = x / 2;
int x_sub = x % 2;
uint32_t pos = (x1 + y * (this->get_width_internal() / 2));
uint8_t current = this->buffer_[pos];
// float px = (0.2126 * (color.red / 255.0)) + (0.7152 * (color.green / 255.0)) + (0.0722 * (color.blue / 255.0));
// px = pow(px, 1.5);
// uint8_t gs = (uint8_t)(px*7);
uint8_t gs = ((color.red * 2126 / 10000) + (color.green * 7152 / 10000) + (color.blue * 722 / 10000)) >> 5;
this->buffer_[pos] = (pixelMaskGLUT[x_sub] & current) | (x_sub ? gs : gs << 4);
} else {
int x1 = x / 8;
int x_sub = x % 8;
uint32_t pos = (x1 + y * (this->get_width_internal() / 8));
uint8_t current = this->partial_buffer_[pos];
this->partial_buffer_[pos] = (~pixelMaskLUT[x_sub] & current) | (color.is_on() ? 0 : pixelMaskLUT[x_sub]);
}
}
void Inkplate6::dump_config() {
LOG_DISPLAY("", "Inkplate", this);
ESP_LOGCONFIG(TAG, " Greyscale: %s", YESNO(this->greyscale_));
ESP_LOGCONFIG(TAG, " Partial Updating: %s", YESNO(this->partial_updating_));
ESP_LOGCONFIG(TAG, " Full Update Every: %d", this->full_update_every_);
// Log pins
LOG_PIN(" CKV Pin: ", this->ckv_pin_);
LOG_PIN(" CL Pin: ", this->cl_pin_);
LOG_PIN(" GPIO0 Enable Pin: ", this->gpio0_enable_pin_);
LOG_PIN(" GMOD Pin: ", this->gmod_pin_);
LOG_PIN(" LE Pin: ", this->le_pin_);
LOG_PIN(" OE Pin: ", this->oe_pin_);
LOG_PIN(" POWERUP Pin: ", this->powerup_pin_);
LOG_PIN(" SPH Pin: ", this->sph_pin_);
LOG_PIN(" SPV Pin: ", this->spv_pin_);
LOG_PIN(" VCOM Pin: ", this->vcom_pin_);
LOG_PIN(" WAKEUP Pin: ", this->wakeup_pin_);
LOG_PIN(" Data 0 Pin: ", this->display_data_0_pin_);
LOG_PIN(" Data 1 Pin: ", this->display_data_1_pin_);
LOG_PIN(" Data 2 Pin: ", this->display_data_2_pin_);
LOG_PIN(" Data 3 Pin: ", this->display_data_3_pin_);
LOG_PIN(" Data 4 Pin: ", this->display_data_4_pin_);
LOG_PIN(" Data 5 Pin: ", this->display_data_5_pin_);
LOG_PIN(" Data 6 Pin: ", this->display_data_6_pin_);
LOG_PIN(" Data 7 Pin: ", this->display_data_7_pin_);
LOG_UPDATE_INTERVAL(this);
}
void Inkplate6::eink_off_() {
ESP_LOGV(TAG, "Eink off called");
unsigned long start_time = millis();
if (panel_on_ == 0)
return;
panel_on_ = 0;
this->gmod_pin_->digital_write(false);
this->oe_pin_->digital_write(false);
GPIO.out &= ~(get_data_pin_mask_() | (1 << this->cl_pin_->get_pin()) | (1 << this->le_pin_->get_pin()));
this->sph_pin_->digital_write(false);
this->spv_pin_->digital_write(false);
this->powerup_pin_->digital_write(false);
this->wakeup_pin_->digital_write(false);
this->vcom_pin_->digital_write(false);
pins_z_state_();
}
void Inkplate6::eink_on_() {
ESP_LOGV(TAG, "Eink on called");
unsigned long start_time = millis();
if (panel_on_ == 1)
return;
panel_on_ = 1;
pins_as_outputs_();
this->wakeup_pin_->digital_write(true);
this->powerup_pin_->digital_write(true);
this->vcom_pin_->digital_write(true);
this->write_byte(0x01, 0x3F);
delay(40);
this->write_byte(0x0D, 0x80);
delay(2);
this->read_byte(0x00, &temperature_, 0);
this->le_pin_->digital_write(false);
this->oe_pin_->digital_write(false);
this->cl_pin_->digital_write(false);
this->sph_pin_->digital_write(true);
this->gmod_pin_->digital_write(true);
this->spv_pin_->digital_write(true);
this->ckv_pin_->digital_write(false);
this->oe_pin_->digital_write(true);
}
void Inkplate6::fill(Color color) {
ESP_LOGV(TAG, "Fill called");
unsigned long start_time = millis();
if (this->greyscale_) {
uint8_t fill = ((color.red * 2126 / 10000) + (color.green * 7152 / 10000) + (color.blue * 722 / 10000)) >> 5;
for (uint32_t i = 0; i < this->get_buffer_length_(); i++)
this->buffer_[i] = (fill << 4) | fill;
} else {
uint8_t fill = color.is_on() ? 0x00 : 0xFF;
for (uint32_t i = 0; i < this->get_buffer_length_(); i++)
this->partial_buffer_[i] = fill;
}
ESP_LOGV(TAG, "Fill finished (%lums)", millis() - start_time);
}
void Inkplate6::display() {
ESP_LOGV(TAG, "Display called");
unsigned long start_time = millis();
if (this->greyscale_) {
this->display3b_();
} else {
if (this->partial_updating_ && this->partial_update_()) {
ESP_LOGV(TAG, "Display finished (partial) (%lums)", millis() - start_time);
return;
}
this->display1b_();
}
ESP_LOGV(TAG, "Display finished (full) (%lums)", millis() - start_time);
}
void Inkplate6::display1b_() {
ESP_LOGV(TAG, "Display1b called");
unsigned long start_time = millis();
for (int i = 0; i < this->get_buffer_length_(); i++) {
this->buffer_[i] &= this->partial_buffer_[i];
this->buffer_[i] |= this->partial_buffer_[i];
}
uint16_t pos;
uint32_t send;
uint8_t data;
uint8_t buffer_value;
eink_on_();
clean_fast_(0, 1);
clean_fast_(1, 5);
clean_fast_(2, 1);
clean_fast_(0, 5);
clean_fast_(2, 1);
clean_fast_(1, 12);
clean_fast_(2, 1);
clean_fast_(0, 11);
ESP_LOGV(TAG, "Display1b start loops (%lums)", millis() - start_time);
for (int k = 0; k < 3; k++) {
pos = this->get_buffer_length_() - 1;
vscan_start_();
for (int i = 0; i < this->get_height_internal(); i++) {
buffer_value = this->buffer_[pos];
data = LUTB[(buffer_value >> 4) & 0x0F];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
hscan_start_(send);
data = LUTB[buffer_value & 0x0F];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
pos--;
for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) {
buffer_value = this->buffer_[pos];
data = LUTB[(buffer_value >> 4) & 0x0F];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
data = LUTB[buffer_value & 0x0F];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
pos--;
}
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
vscan_end_();
}
delayMicroseconds(230);
}
ESP_LOGV(TAG, "Display1b first loop x %d (%lums)", 3, millis() - start_time);
pos = this->get_buffer_length_() - 1;
vscan_start_();
for (int i = 0; i < this->get_height_internal(); i++) {
buffer_value = this->buffer_[pos];
data = LUT2[(buffer_value >> 4) & 0x0F];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
hscan_start_(send);
data = LUT2[buffer_value & 0x0F];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
pos--;
for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) {
buffer_value = this->buffer_[pos];
data = LUT2[(buffer_value >> 4) & 0x0F];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
data = LUT2[buffer_value & 0x0F];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
pos--;
}
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
vscan_end_();
}
delayMicroseconds(230);
ESP_LOGV(TAG, "Display1b second loop (%lums)", millis() - start_time);
vscan_start_();
for (int i = 0; i < this->get_height_internal(); i++) {
buffer_value = this->buffer_[pos];
data = 0b00000000;
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
hscan_start_(send);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) {
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
}
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
vscan_end_();
}
delayMicroseconds(230);
ESP_LOGV(TAG, "Display1b third loop (%lums)", millis() - start_time);
vscan_start_();
eink_off_();
this->block_partial_ = false;
this->partial_updates_ = 0;
ESP_LOGV(TAG, "Display1b finished (%lums)", millis() - start_time);
}
void Inkplate6::display3b_() {
ESP_LOGV(TAG, "Display3b called");
unsigned long start_time = millis();
eink_on_();
clean_fast_(0, 1);
clean_fast_(1, 12);
clean_fast_(2, 1);
clean_fast_(0, 11);
clean_fast_(2, 1);
clean_fast_(1, 12);
clean_fast_(2, 1);
clean_fast_(0, 11);
for (int k = 0; k < 8; k++) {
uint32_t pos = this->get_buffer_length_() - 1;
uint32_t send;
uint8_t pix1;
uint8_t pix2;
uint8_t pix3;
uint8_t pix4;
uint8_t pixel;
uint8_t pixel2;
vscan_start_();
for (int i = 0; i < this->get_height_internal(); i++) {
pix1 = this->buffer_[pos--];
pix2 = this->buffer_[pos--];
pix3 = this->buffer_[pos--];
pix4 = this->buffer_[pos--];
pixel = (waveform3Bit[pix1 & 0x07][k] << 6) | (waveform3Bit[(pix1 >> 4) & 0x07][k] << 4) |
(waveform3Bit[pix2 & 0x07][k] << 2) | (waveform3Bit[(pix2 >> 4) & 0x07][k] << 0);
pixel2 = (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) |
(waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0);
send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | (((pixel & B00010000) >> 4) << 23) |
(((pixel & B11100000) >> 5) << 25);
hscan_start_(send);
send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | (((pixel2 & B00010000) >> 4) << 23) |
(((pixel2 & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) {
pix1 = this->buffer_[pos--];
pix2 = this->buffer_[pos--];
pix3 = this->buffer_[pos--];
pix4 = this->buffer_[pos--];
pixel = (waveform3Bit[pix1 & 0x07][k] << 6) | (waveform3Bit[(pix1 >> 4) & 0x07][k] << 4) |
(waveform3Bit[pix2 & 0x07][k] << 2) | (waveform3Bit[(pix2 >> 4) & 0x07][k] << 0);
pixel2 = (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) |
(waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0);
send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | (((pixel & B00010000) >> 4) << 23) |
(((pixel & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | (((pixel2 & B00010000) >> 4) << 23) |
(((pixel2 & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
}
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
vscan_end_();
}
delayMicroseconds(230);
}
clean_fast_(2, 1);
clean_fast_(3, 1);
vscan_start_();
eink_off_();
ESP_LOGV(TAG, "Display3b finished (%lums)", millis() - start_time);
}
bool Inkplate6::partial_update_() {
ESP_LOGV(TAG, "Partial update called");
unsigned long start_time = millis();
if (this->greyscale_)
return false;
if (this->block_partial_)
return false;
this->partial_updates_++;
uint16_t pos = this->get_buffer_length_() - 1;
uint32_t send;
uint8_t data;
uint8_t diffw, diffb;
uint32_t n = (this->get_buffer_length_() * 2) - 1;
for (int i = 0; i < this->get_height_internal(); i++) {
for (int j = 0; j < (this->get_width_internal() / 8); j++) {
diffw = (this->buffer_[pos] ^ this->partial_buffer_[pos]) & ~(this->partial_buffer_[pos]);
diffb = (this->buffer_[pos] ^ this->partial_buffer_[pos]) & this->partial_buffer_[pos];
pos--;
this->partial_buffer_2_[n--] = LUTW[diffw >> 4] & LUTB[diffb >> 4];
this->partial_buffer_2_[n--] = LUTW[diffw & 0x0F] & LUTB[diffb & 0x0F];
}
}
ESP_LOGV(TAG, "Partial update buffer built after (%lums)", millis() - start_time);
eink_on_();
for (int k = 0; k < 5; k++) {
vscan_start_();
n = (this->get_buffer_length_() * 2) - 1;
for (int i = 0; i < this->get_height_internal(); i++) {
data = this->partial_buffer_2_[n--];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
hscan_start_(send);
for (int j = 0; j < (this->get_width_internal() / 4) - 1; j++) {
data = this->partial_buffer_2_[n--];
send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
}
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
vscan_end_();
}
delayMicroseconds(230);
ESP_LOGV(TAG, "Partial update loop k=%d (%lums)", k, millis() - start_time);
}
clean_fast_(2, 2);
clean_fast_(3, 1);
vscan_start_();
eink_off_();
for (int i = 0; i < this->get_buffer_length_(); i++) {
this->buffer_[i] = this->partial_buffer_[i];
}
ESP_LOGV(TAG, "Partial update finished (%lums)", millis() - start_time);
return true;
}
void Inkplate6::vscan_start_() {
this->ckv_pin_->digital_write(true);
delayMicroseconds(7);
this->spv_pin_->digital_write(false);
delayMicroseconds(10);
this->ckv_pin_->digital_write(false);
delayMicroseconds(0);
this->ckv_pin_->digital_write(true);
delayMicroseconds(8);
this->spv_pin_->digital_write(true);
delayMicroseconds(10);
this->ckv_pin_->digital_write(false);
delayMicroseconds(0);
this->ckv_pin_->digital_write(true);
delayMicroseconds(18);
this->ckv_pin_->digital_write(false);
delayMicroseconds(0);
this->ckv_pin_->digital_write(true);
delayMicroseconds(18);
this->ckv_pin_->digital_write(false);
delayMicroseconds(0);
this->ckv_pin_->digital_write(true);
}
void Inkplate6::vscan_write_() {
this->ckv_pin_->digital_write(false);
this->le_pin_->digital_write(true);
this->le_pin_->digital_write(false);
delayMicroseconds(0);
this->sph_pin_->digital_write(false);
this->cl_pin_->digital_write(true);
this->cl_pin_->digital_write(false);
this->sph_pin_->digital_write(true);
this->ckv_pin_->digital_write(true);
}
void Inkplate6::hscan_start_(uint32_t d) {
this->sph_pin_->digital_write(false);
GPIO.out_w1ts = (d) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
this->sph_pin_->digital_write(true);
}
void Inkplate6::vscan_end_() {
this->ckv_pin_->digital_write(false);
this->le_pin_->digital_write(true);
this->le_pin_->digital_write(false);
delayMicroseconds(1);
this->ckv_pin_->digital_write(true);
}
void Inkplate6::clean() {
ESP_LOGV(TAG, "Clean called");
unsigned long start_time = millis();
eink_on_();
clean_fast_(0, 1); // White
clean_fast_(0, 8); // White to White
clean_fast_(0, 1); // White to Black
clean_fast_(0, 8); // Black to Black
clean_fast_(2, 1); // Black to White
clean_fast_(1, 10); // White to White
ESP_LOGV(TAG, "Clean finished (%lums)", millis() - start_time);
}
void Inkplate6::clean_fast_(uint8_t c, uint8_t rep) {
ESP_LOGV(TAG, "Clean fast called with: (%d, %d)", c, rep);
unsigned long start_time = millis();
eink_on_();
uint8_t data = 0;
if (c == 0) // White
data = B10101010;
else if (c == 1) // Black
data = B01010101;
else if (c == 2) // Discharge
data = B00000000;
else if (c == 3) // Skip
data = B11111111;
uint32_t send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) |
(((data & B11100000) >> 5) << 25);
for (int k = 0; k < rep; k++) {
vscan_start_();
for (int i = 0; i < this->get_height_internal(); i++) {
hscan_start_(send);
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
for (int j = 0; j < this->get_width_internal() / 8; j++) {
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
}
GPIO.out_w1ts = (send) | (1 << this->cl_pin_->get_pin());
GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin());
vscan_end_();
}
delayMicroseconds(230);
ESP_LOGV(TAG, "Clean fast rep loop %d finished (%lums)", k, millis() - start_time);
}
ESP_LOGV(TAG, "Clean fast finished (%lums)", millis() - start_time);
}
void Inkplate6::pins_z_state_() {
this->ckv_pin_->pin_mode(INPUT);
this->sph_pin_->pin_mode(INPUT);
this->oe_pin_->pin_mode(INPUT);
this->gmod_pin_->pin_mode(INPUT);
this->spv_pin_->pin_mode(INPUT);
this->display_data_0_pin_->pin_mode(INPUT);
this->display_data_1_pin_->pin_mode(INPUT);
this->display_data_2_pin_->pin_mode(INPUT);
this->display_data_3_pin_->pin_mode(INPUT);
this->display_data_4_pin_->pin_mode(INPUT);
this->display_data_5_pin_->pin_mode(INPUT);
this->display_data_6_pin_->pin_mode(INPUT);
this->display_data_7_pin_->pin_mode(INPUT);
}
void Inkplate6::pins_as_outputs_() {
this->ckv_pin_->pin_mode(OUTPUT);
this->sph_pin_->pin_mode(OUTPUT);
this->oe_pin_->pin_mode(OUTPUT);
this->gmod_pin_->pin_mode(OUTPUT);
this->spv_pin_->pin_mode(OUTPUT);
this->display_data_0_pin_->pin_mode(OUTPUT);
this->display_data_1_pin_->pin_mode(OUTPUT);
this->display_data_2_pin_->pin_mode(OUTPUT);
this->display_data_3_pin_->pin_mode(OUTPUT);
this->display_data_4_pin_->pin_mode(OUTPUT);
this->display_data_5_pin_->pin_mode(OUTPUT);
this->display_data_6_pin_->pin_mode(OUTPUT);
this->display_data_7_pin_->pin_mode(OUTPUT);
}
} // namespace inkplate6
} // namespace esphome
#endif

View File

@@ -0,0 +1,157 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/display/display_buffer.h"
#ifdef ARDUINO_ARCH_ESP32
namespace esphome {
namespace inkplate6 {
class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public i2c::I2CDevice {
public:
const uint8_t LUT2[16] = {B10101010, B10101001, B10100110, B10100101, B10011010, B10011001, B10010110, B10010101,
B01101010, B01101001, B01100110, B01100101, B01011010, B01011001, B01010110, B01010101};
const uint8_t LUTW[16] = {B11111111, B11111110, B11111011, B11111010, B11101111, B11101110, B11101011, B11101010,
B10111111, B10111110, B10111011, B10111010, B10101111, B10101110, B10101011, B10101010};
const uint8_t LUTB[16] = {B11111111, B11111101, B11110111, B11110101, B11011111, B11011101, B11010111, B11010101,
B01111111, B01111101, B01110111, B01110101, B01011111, B01011101, B01010111, B01010101};
const uint8_t pixelMaskLUT[8] = {B00000001, B00000010, B00000100, B00001000,
B00010000, B00100000, B01000000, B10000000};
const uint8_t pixelMaskGLUT[2] = {B00001111, B11110000};
const uint8_t waveform3Bit[8][8] = {{0, 0, 0, 0, 1, 1, 1, 0}, {1, 2, 2, 2, 1, 1, 1, 0}, {0, 1, 2, 1, 1, 2, 1, 0},
{0, 2, 1, 2, 1, 2, 1, 0}, {0, 0, 0, 1, 1, 1, 2, 0}, {2, 1, 1, 1, 2, 1, 2, 0},
{1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0}};
const uint32_t waveform[50] = {
0x00000008, 0x00000008, 0x00200408, 0x80281888, 0x60a81898, 0x60a8a8a8, 0x60a8a8a8, 0x6068a868, 0x6868a868,
0x6868a868, 0x68686868, 0x6a686868, 0x5a686868, 0x5a686868, 0x5a586a68, 0x5a5a6a68, 0x5a5a6a68, 0x55566a68,
0x55565a64, 0x55555654, 0x55555556, 0x55555556, 0x55555556, 0x55555516, 0x55555596, 0x15555595, 0x95955595,
0x95959595, 0x95949495, 0x94949495, 0x94949495, 0xa4949494, 0x9494a4a4, 0x84a49494, 0x84948484, 0x84848484,
0x84848484, 0x84848484, 0xa5a48484, 0xa9a4a4a8, 0xa9a8a8a8, 0xa5a9a9a4, 0xa5a5a5a4, 0xa1a5a5a1, 0xa9a9a9a9,
0xa9a9a9a9, 0xa9a9a9a9, 0xa9a9a9a9, 0x15151515, 0x11111111};
void set_greyscale(bool greyscale) {
this->greyscale_ = greyscale;
this->initialize_();
this->block_partial_ = true;
}
void set_partial_updating(bool partial_updating) { this->partial_updating_ = partial_updating; }
void set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
void set_display_data_0_pin(GPIOPin *data) { this->display_data_0_pin_ = data; }
void set_display_data_1_pin(GPIOPin *data) { this->display_data_1_pin_ = data; }
void set_display_data_2_pin(GPIOPin *data) { this->display_data_2_pin_ = data; }
void set_display_data_3_pin(GPIOPin *data) { this->display_data_3_pin_ = data; }
void set_display_data_4_pin(GPIOPin *data) { this->display_data_4_pin_ = data; }
void set_display_data_5_pin(GPIOPin *data) { this->display_data_5_pin_ = data; }
void set_display_data_6_pin(GPIOPin *data) { this->display_data_6_pin_ = data; }
void set_display_data_7_pin(GPIOPin *data) { this->display_data_7_pin_ = data; }
void set_ckv_pin(GPIOPin *ckv) { this->ckv_pin_ = ckv; }
void set_cl_pin(GPIOPin *cl) { this->cl_pin_ = cl; }
void set_gpio0_enable_pin(GPIOPin *gpio0_enable) { this->gpio0_enable_pin_ = gpio0_enable; }
void set_gmod_pin(GPIOPin *gmod) { this->gmod_pin_ = gmod; }
void set_le_pin(GPIOPin *le) { this->le_pin_ = le; }
void set_oe_pin(GPIOPin *oe) { this->oe_pin_ = oe; }
void set_powerup_pin(GPIOPin *powerup) { this->powerup_pin_ = powerup; }
void set_sph_pin(GPIOPin *sph) { this->sph_pin_ = sph; }
void set_spv_pin(GPIOPin *spv) { this->spv_pin_ = spv; }
void set_vcom_pin(GPIOPin *vcom) { this->vcom_pin_ = vcom; }
void set_wakeup_pin(GPIOPin *wakeup) { this->wakeup_pin_ = wakeup; }
float get_setup_priority() const override;
void dump_config() override;
void display();
void clean();
void fill(Color color) override;
void update() override;
void setup() override;
uint8_t get_panel_state() { return this->panel_on_; }
bool get_greyscale() { return this->greyscale_; }
bool get_partial_updating() { return this->partial_updating_; }
uint8_t get_temperature() { return this->temperature_; }
protected:
void draw_absolute_pixel_internal(int x, int y, Color color) override;
void display1b_();
void display3b_();
void initialize_();
bool partial_update_();
void clean_fast_(uint8_t c, uint8_t rep);
void hscan_start_(uint32_t d);
void vscan_end_();
void vscan_start_();
void vscan_write_();
void eink_off_();
void eink_on_();
void setup_pins_();
void pins_z_state_();
void pins_as_outputs_();
int get_width_internal() override { return 800; }
int get_height_internal() override { return 600; }
size_t get_buffer_length_();
int get_data_pin_mask_() {
int data = 0;
data |= (1 << this->display_data_0_pin_->get_pin());
data |= (1 << this->display_data_1_pin_->get_pin());
data |= (1 << this->display_data_2_pin_->get_pin());
data |= (1 << this->display_data_3_pin_->get_pin());
data |= (1 << this->display_data_4_pin_->get_pin());
data |= (1 << this->display_data_5_pin_->get_pin());
data |= (1 << this->display_data_6_pin_->get_pin());
data |= (1 << this->display_data_7_pin_->get_pin());
return data;
}
uint8_t panel_on_ = 0;
uint8_t temperature_;
uint8_t *partial_buffer_{nullptr};
uint8_t *partial_buffer_2_{nullptr};
uint32_t full_update_every_;
uint32_t partial_updates_{0};
bool block_partial_;
bool greyscale_;
bool partial_updating_;
GPIOPin *display_data_0_pin_;
GPIOPin *display_data_1_pin_;
GPIOPin *display_data_2_pin_;
GPIOPin *display_data_3_pin_;
GPIOPin *display_data_4_pin_;
GPIOPin *display_data_5_pin_;
GPIOPin *display_data_6_pin_;
GPIOPin *display_data_7_pin_;
GPIOPin *ckv_pin_;
GPIOPin *cl_pin_;
GPIOPin *gpio0_enable_pin_;
GPIOPin *gmod_pin_;
GPIOPin *le_pin_;
GPIOPin *oe_pin_;
GPIOPin *powerup_pin_;
GPIOPin *sph_pin_;
GPIOPin *spv_pin_;
GPIOPin *vcom_pin_;
GPIOPin *wakeup_pin_;
};
} // namespace inkplate6
} // namespace esphome
#endif

View File

@@ -149,10 +149,10 @@ struct ESPColor {
return ESPColor(uint8_t((uint16_t(r) * 255U / max_rgb)), uint8_t((uint16_t(g) * 255U / max_rgb)),
uint8_t((uint16_t(b) * 255U / max_rgb)), w);
}
ESPColor fade_to_white(uint8_t amnt) { return ESPColor(255, 255, 255, 255) - (*this * amnt); }
ESPColor fade_to_black(uint8_t amnt) { return *this * amnt; }
ESPColor lighten(uint8_t delta) { return *this + delta; }
ESPColor darken(uint8_t delta) { return *this - delta; }
ESPColor fade_to_white(uint8_t amnt) const { return ESPColor(255, 255, 255, 255) - (*this * amnt); }
ESPColor fade_to_black(uint8_t amnt) const { return *this * amnt; }
ESPColor lighten(uint8_t delta) const { return *this + delta; }
ESPColor darken(uint8_t delta) const { return *this - delta; }
static const ESPColor BLACK;
static const ESPColor WHITE;

View File

@@ -102,13 +102,18 @@ class LightTurnOnTrigger : public Trigger<> {
public:
LightTurnOnTrigger(LightState *a_light) {
a_light->add_new_remote_values_callback([this, a_light]() {
auto is_on = a_light->current_values.is_on();
if (is_on && !last_on_) {
// using the remote value because of transitions we need to trigger as early as possible
auto is_on = a_light->remote_values.is_on();
// only trigger when going from off to on
auto should_trigger = is_on && !this->last_on_;
// Set new state immediately so that trigger() doesn't devolve
// into infinite loop
this->last_on_ = is_on;
if (should_trigger) {
this->trigger();
}
last_on_ = is_on;
});
last_on_ = a_light->current_values.is_on();
this->last_on_ = a_light->current_values.is_on();
}
protected:
@@ -118,18 +123,14 @@ class LightTurnOnTrigger : public Trigger<> {
class LightTurnOffTrigger : public Trigger<> {
public:
LightTurnOffTrigger(LightState *a_light) {
a_light->add_new_remote_values_callback([this, a_light]() {
a_light->add_new_target_state_reached_callback([this, a_light]() {
auto is_on = a_light->current_values.is_on();
if (!is_on && last_on_) {
// only trigger when going from on to off
if (!is_on) {
this->trigger();
}
last_on_ = is_on;
});
last_on_ = a_light->current_values.is_on();
}
protected:
bool last_on_;
};
template<typename... Ts> class AddressableSet : public Action<Ts...> {

View File

@@ -145,6 +145,7 @@ void LightState::loop() {
if (this->transformer_ != nullptr) {
if (this->transformer_->is_finished()) {
this->remote_values = this->current_values = this->transformer_->get_end_values();
this->target_state_reached_callback_.call();
if (this->transformer_->publish_at_end())
this->publish_state();
this->transformer_ = nullptr;
@@ -336,6 +337,9 @@ void LightCall::perform() {
this->parent_->set_immediately_(v, this->publish_);
}
if (!this->has_transition_()) {
this->parent_->target_state_reached_callback_.call();
}
if (this->publish_) {
this->parent_->publish_state();
}
@@ -395,13 +399,13 @@ LightColorValues LightCall::validate_() {
// sets RGB to 100% if only White specified
if (this->white_.has_value()) {
if (!this->red_.has_value() && !this->green_.has_value() && !this->blue_.has_value()) {
this->red_ = optional<float>(1.0f);
this->green_ = optional<float>(1.0f);
this->blue_ = optional<float>(1.0f);
}
// make white values binary aka 0.0f or 1.0f...this allows brightness to do its job
if (traits.get_supports_color_interlock()) {
if (!this->red_.has_value() && !this->green_.has_value() && !this->blue_.has_value()) {
this->red_ = optional<float>(1.0f);
this->green_ = optional<float>(1.0f);
this->blue_ = optional<float>(1.0f);
}
// make white values binary aka 0.0f or 1.0f...this allows brightness to do its job
if (*this->white_ > 0.0f) {
this->white_ = optional<float>(1.0f);
} else {
@@ -411,11 +415,13 @@ LightColorValues LightCall::validate_() {
}
// White to 0% if (exclusively) setting any RGB value that isn't 255,255,255
else if (this->red_.has_value() || this->green_.has_value() || this->blue_.has_value()) {
if (*this->red_ == 1.0f && *this->green_ == 1.0f && *this->blue_ == 1.0f && traits.get_supports_rgb_white_value() &&
traits.get_supports_color_interlock()) {
this->white_ = optional<float>(1.0f);
} else if (!this->white_.has_value() || !traits.get_supports_rgb_white_value()) {
this->white_ = optional<float>(0.0f);
if (traits.get_supports_color_interlock()) {
if (*this->red_ == 1.0f && *this->green_ == 1.0f && *this->blue_ == 1.0f &&
traits.get_supports_rgb_white_value() && traits.get_supports_color_interlock()) {
this->white_ = optional<float>(1.0f);
} else if (!this->white_.has_value() || !traits.get_supports_rgb_white_value()) {
this->white_ = optional<float>(0.0f);
}
}
}
// if changing Kelvin alone, change to white light
@@ -752,6 +758,10 @@ void LightState::current_values_as_cwww(float *cold_white, float *warm_white, bo
void LightState::add_new_remote_values_callback(std::function<void()> &&send_callback) {
this->remote_values_callback_.add(std::move(send_callback));
}
void LightState::add_new_target_state_reached_callback(std::function<void()> &&send_callback) {
this->target_state_reached_callback_.add(std::move(send_callback));
}
LightEffect *LightState::get_active_effect_() {
if (this->active_effect_index_ == 0)
return nullptr;

View File

@@ -242,6 +242,13 @@ class LightState : public Nameable, public Component {
*/
void add_new_remote_values_callback(std::function<void()> &&send_callback);
/**
* The callback is called once the state of current_values and remote_values are equal
*
* @param send_callback
*/
void add_new_target_state_reached_callback(std::function<void()> &&send_callback);
/// Return whether the light has any effects that meet the trait requirements.
bool supports_effects();
@@ -318,6 +325,12 @@ class LightState : public Nameable, public Component {
* starting with the beginning of the transition.
*/
CallbackManager<void()> remote_values_callback_{};
/** Callback to call when the state of current_values and remote_values are equal
* This should be called once the state of current_values changed and equals the state of remote_values
*/
CallbackManager<void()> target_state_reached_callback_{};
LightOutput *output_; ///< Store the output to allow effects to have more access.
/// Whether the light value should be written in the next cycle.
bool next_write_{true};

View File

@@ -41,10 +41,10 @@ void MAX31855Sensor::read_data_() {
this->read_array(data, 4);
this->disable();
const uint32_t mem = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3] << 0;
const uint32_t mem = encode_uint32(data[0], data[1], data[2], data[3]);
// Verify we got data
if (mem != 0 && mem != 0xFFFFFFFF) {
if (mem != 0xFFFFFFFF) {
this->status_clear_error();
} else {
ESP_LOGE(TAG, "No data received from MAX31855 (0x%08X). Check wiring!", mem);

View File

@@ -9,11 +9,14 @@ max7219_ns = cg.esphome_ns.namespace('max7219')
MAX7219Component = max7219_ns.class_('MAX7219Component', cg.PollingComponent, spi.SPIDevice)
MAX7219ComponentRef = MAX7219Component.operator('ref')
CONF_REVERSE_ENABLE = 'reverse_enable'
CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(MAX7219Component),
cv.Optional(CONF_NUM_CHIPS, default=1): cv.int_range(min=1, max=255),
cv.Optional(CONF_INTENSITY, default=15): cv.int_range(min=0, max=15),
cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean,
}).extend(cv.polling_component_schema('1s')).extend(spi.spi_device_schema())
@@ -25,6 +28,7 @@ def to_code(config):
cg.add(var.set_num_chips(config[CONF_NUM_CHIPS]))
cg.add(var.set_intensity(config[CONF_INTENSITY]))
cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE]))
if CONF_LAMBDA in config:
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [(MAX7219ComponentRef, 'it')],

View File

@@ -142,9 +142,11 @@ void MAX7219Component::dump_config() {
void MAX7219Component::display() {
for (uint8_t i = 0; i < 8; i++) {
this->enable();
for (uint8_t j = 0; j < this->num_chips_; j++) {
this->send_byte_(8 - i, this->buffer_[j * 8 + i]);
}
for (uint8_t j = 0; j < this->num_chips_; j++)
if (reverse_)
this->send_byte_(8 - i, buffer_[(num_chips_ - j - 1) * 8 + i]);
else
this->send_byte_(8 - i, buffer_[j * 8 + i]);
this->disable();
}
}

View File

@@ -34,6 +34,7 @@ class MAX7219Component : public PollingComponent,
void set_intensity(uint8_t intensity);
void set_num_chips(uint8_t num_chips);
void set_reverse(bool reverse) { this->reverse_ = reverse; };
/// Evaluate the printf-format and print the result at the given position.
uint8_t printf(uint8_t pos, const char *format, ...) __attribute__((format(printf, 3, 4)));
@@ -60,6 +61,7 @@ class MAX7219Component : public PollingComponent,
uint8_t intensity_{15}; /// Intensity of the display from 0 to 15 (most)
uint8_t num_chips_{1};
uint8_t *buffer_;
bool reverse_{false};
optional<max7219_writer_t> writer_{};
};

View File

@@ -11,6 +11,7 @@ CONF_SCROLL_DWELL = 'scroll_dwell'
CONF_SCROLL_DELAY = 'scroll_delay'
CONF_SCROLL_ENABLE = 'scroll_enable'
CONF_SCROLL_MODE = 'scroll_mode'
CONF_REVERSE_ENABLE = 'reverse_enable'
SCROLL_MODES = {
'CONTINUOUS': 0,
@@ -39,6 +40,7 @@ CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({
cv.Optional(CONF_SCROLL_SPEED, default='250ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_SCROLL_DELAY, default='1000ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_SCROLL_DWELL, default='1000ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean,
}).extend(cv.polling_component_schema('500ms')).extend(spi.spi_device_schema(cs_pin_required=True))
@@ -56,6 +58,7 @@ def to_code(config):
cg.add(var.set_scroll_delay(config[CONF_SCROLL_DELAY]))
cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE]))
cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE]))
cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE]))
if CONF_LAMBDA in config:
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [(MAX7219ComponentRef, 'it')],

View File

@@ -108,7 +108,11 @@ void MAX7219Component::display() {
// Send the data to the chip
for (uint8_t i = 0; i < this->num_chips_; i++) {
for (uint8_t j = 0; j < 8; j++) {
pixels[j] = this->max_displaybuffer_[i * 8 + j];
if (this->reverse_) {
pixels[j] = this->max_displaybuffer_[(this->num_chips_ - i - 1) * 8 + j];
} else {
pixels[j] = this->max_displaybuffer_[i * 8 + j];
}
}
this->send64pixels(i, pixels);
}
@@ -128,7 +132,7 @@ void HOT MAX7219Component::draw_absolute_pixel_internal(int x, int y, Color colo
this->max_displaybuffer_.resize(x + 1, this->bckgrnd_);
}
if (y >= this->get_height_internal() || y < 0) // If pixel is outside display then dont draw
if ((y >= this->get_height_internal()) || (y < 0) || (x < 0)) // If pixel is outside display then dont draw
return;
uint16_t pos = x; // X is starting at 0 top left
@@ -229,7 +233,7 @@ void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) {
b = pixels[col];
} else if (this->orientation_ == 2) {
for (uint8_t i = 0; i < 8; i++) {
b |= ((pixels[i] >> (7 - col)) << (7 - i));
b |= ((pixels[i] >> (7 - col)) & 1) << i;
}
} else {
b = pixels[7 - col];

View File

@@ -52,6 +52,7 @@ class MAX7219Component : public PollingComponent,
void set_scroll_delay(uint16_t delay) { this->scroll_delay_ = delay; };
void set_scroll(bool on_off) { this->scroll_ = on_off; };
void set_scroll_mode(uint8_t mode) { this->scroll_mode_ = mode; };
void set_reverse(bool on_off) { this->reverse_ = on_off; };
void send_char(byte chip, byte data);
void send64pixels(byte chip, const byte pixels[8]);
@@ -87,6 +88,7 @@ class MAX7219Component : public PollingComponent,
uint8_t intensity_; /// Intensity of the display from 0 to 15 (most)
uint8_t num_chips_;
bool scroll_;
bool reverse_;
bool update_{false};
uint16_t scroll_speed_;
uint16_t scroll_delay_;

View File

@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import i2c
from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED
from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED, CONF_OPEN_DRAIN_INTERRUPT
DEPENDENCIES = ['i2c']
MULTI_CONF = True
@@ -20,6 +20,7 @@ MCP23008GPIOPin = mcp23008_ns.class_('MCP23008GPIOPin', cg.GPIOPin)
CONFIG_SCHEMA = cv.Schema({
cv.Required(CONF_ID): cv.declare_id(MCP23008),
cv.Optional(CONF_OPEN_DRAIN_INTERRUPT, default=False): cv.boolean,
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x20))
@@ -27,6 +28,7 @@ def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
cg.add(var.set_open_drain_ints(config[CONF_OPEN_DRAIN_INTERRUPT]))
CONF_MCP23008 = 'mcp23008'

View File

@@ -14,8 +14,10 @@ void MCP23008::setup() {
return;
}
// all pins input
this->write_reg_(MCP23008_IODIR, 0xFF);
if (this->open_drain_ints_) {
// enable open-drain interrupt pins, 3.3V-safe
this->write_reg_(MCP23008_IOCON, 0x04);
}
}
bool MCP23008::digital_read(uint8_t pin) {
uint8_t bit = pin % 8;

View File

@@ -39,6 +39,8 @@ class MCP23008 : public Component, public i2c::I2CDevice {
void digital_write(uint8_t pin, bool value);
void pin_mode(uint8_t pin, uint8_t mode);
void set_open_drain_ints(const bool value) { open_drain_ints_ = value; }
float get_setup_priority() const override;
protected:
@@ -50,6 +52,7 @@ class MCP23008 : public Component, public i2c::I2CDevice {
void update_reg_(uint8_t pin, bool pin_value, uint8_t reg_a);
uint8_t olat_{0x00};
bool open_drain_ints_;
};
class MCP23008GPIOPin : public GPIOPin {

View File

@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import i2c
from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED
from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED, CONF_OPEN_DRAIN_INTERRUPT
DEPENDENCIES = ['i2c']
MULTI_CONF = True
@@ -20,6 +20,7 @@ MCP23017GPIOPin = mcp23017_ns.class_('MCP23017GPIOPin', cg.GPIOPin)
CONFIG_SCHEMA = cv.Schema({
cv.Required(CONF_ID): cv.declare_id(MCP23017),
cv.Optional(CONF_OPEN_DRAIN_INTERRUPT, default=False): cv.boolean,
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x20))
@@ -27,6 +28,7 @@ def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield i2c.register_i2c_device(var, config)
cg.add(var.set_open_drain_ints(config[CONF_OPEN_DRAIN_INTERRUPT]))
CONF_MCP23017 = 'mcp23017'

Some files were not shown because too many files have changed in this diff Show More