Compare commits

...
45 Commits
Author SHA1 Message Date
randy 0536e91fd1 CI: work on Gitea's runner image too
CI / YAML lint (push) Successful in 5s
CI / ESPHome config validation (push) Successful in 10s
Install yamllint with pip instead of ibiqlik/action-yamllint, which expects
it preinstalled like on GitHub's runner, and pip install with
--ignore-installed so pip doesn't try to remove Debian's packages.
2026-09-30 14:50:33 +02:00
randy 7374ddf4d6 Drop the speaker override, esphome#19862 is merged
CI / YAML lint (push) Failing after 32s
CI / ESPHome config validation (push) Failing after 37s
2026-09-30 12:35:53 +02:00
randy a005b940b2 rfid-reader: take the NDEF records by reference
get_records() now returns a StaticVector of unique_ptr, which can't be copied.
2026-09-30 12:15:49 +02:00
randy 46cf3b1fe8 OTA: require encryption with the api key, plaintext + password only for migration
allow_plaintext_upload lets the uploader give a device that doesn't encrypt
yet its one migration install. Remove it together with the password once
every device has been updated (the uploader says so).
2026-09-30 12:05:39 +02:00
randy bb76912023 Set framework.advanced.flash_chip on ESP32 devices to save IRAM
Values come from ESPHome's own hint in the log of each online device
("Set flash_chip: ... to save IRAM"). Devices that were off got the value of
an identical board (ESP32-PICO-D4 ATOM/Stamp Pico: gd, JC3248W535: generic,
POW Elite: gd), marked as not read from the device.
2026-09-30 11:57:30 +02:00
randy 831d88689d CI: Node 24 actions, pip on PEP 668 runner images, drop committed build cache
- actions/checkout@v7 and tj-actions/changed-files@v47 (Node 20 is deprecated)
- PIP_BREAK_SYSTEM_PACKAGES for Gitea's runner image (externally-managed Python)
- untrack common/.esphome (a gitlink with no submodule mapping) and ignore
  .esphome/ in every directory
2026-09-30 11:21:55 +02:00
randy 170fd69274 Fix yamllint errors: trailing spaces, blank lines and newline at end of file
Allow aligned values after a colon (the bedroom lamp presets).
2026-09-30 11:08:22 +02:00
randy 89763817f6 bedroom lamps: use the xiaomi_bslamp2 fork with the ESPHome 2026.10 light fix 2026-09-30 10:53:16 +02:00
randy 03ca4e98b5 status_led: show component errors only on a dedicated status LED (show_errors)
The ATOM LED gets them; displays and lights that are also normal lights don't,
so a failed component can't take them over.
2026-09-30 10:12:06 +02:00
randy fb66547dd1 status_led: don't show component errors, only network, API and OTA 2026-09-30 09:00:58 +02:00
randy 725c400de6 atoms3: full-screen status, IPv6-only, animation as image platform, fix colours
The status (common/status_led.yaml) drives a virtual RGB light that fills
the display; the display needs little-endian RGB565 (colours were swapped).
2026-09-30 08:58:16 +02:00
randy 7517c301ac Status LED on every ATOM device (except the vehicle beacons)
common/status_led_atom.yaml puts common/status_led.yaml on the ATOM Lite's
own RGB LED (G27, 64 RMT symbols to leave room for IR/RF). echo-1 uses its
existing LED light.
2026-09-30 08:58:16 +02:00
randy 422b334582 air-office-r: LEDs back on (the stick had lost its GND), status on the NEO stick 2026-09-30 08:29:19 +02:00
randy 2f5e438424 Move remaining NSPanel's to IPv6 Only network 2026-09-30 08:08:12 +02:00
randy 6a3002d9b7 Add status_led package: network, API, error and OTA status on a visible RGB light
CI / ESPHome config validation (push) Failing after 7s
CI / YAML lint (push) Failing after 37s
Red blink without network, orange without an API client, purple on a
component error, blue blink during OTA, green when things are back to
normal, then the light returns to its previous state.

echo uses it on the gateway LED ring; drop its status_led on GPIO23,
which never worked because the ledc output owns that pin.
2026-09-29 23:33:50 +02:00
randy 6845679bc0 echo: only the gateway LED ring is visible, the ATOM LED is inside 2026-09-29 23:24:39 +02:00
randy a3950d9f17 echo: it's a Xiaomi Mijia Gateway with an ATOM Echo brain transplant 2026-09-29 23:23:44 +02:00
randy 0d6aa6e3d7 nspanel-patio: jump straight to the Von card
Temporarily make it the default page and render it once, instead of
rendering home, next and next.
2026-09-29 23:23:14 +02:00
randy 271a5a5a54 nspanel: popups for OTA progress and device info, Info card on every panel
common/nspanel_popup.yaml shows a popupNotify page during OTA (written straight
to the display uart, since OTA blocks the loop that sends the component's
queued commands) and a device info popup (version, build time, IPs) from the
Info button on the new last card or the show_info API action. The OTA gets
id ota_esphome to extend it. Also documents the NSPanel pinout.
2026-09-29 23:23:14 +02:00
randy c5ab280725 air-office-r: document hardware, disable the LEDs until the stick is fixed
The TZT 8-bit WS2812 stick lights up random colours after the first LED.
2026-09-29 23:22:17 +02:00
randy 1a2aec5d01 Document hardware, pinout and I2C devices in a header comment of every device
Merge the old pinout comment blocks into the header and mark what each pin is used for.
2026-09-29 23:22:17 +02:00
randy 882428e491 Move echo's to ipv6 only network 2026-09-29 21:53:38 +02:00
randy 20f6db5a70 ipv6_only: take audio from esphome#19750 2026-09-29 19:42:15 +02:00
randy b8738b39e0 fix: update patio status entity ID to match old naming convention
CI / ESPHome config validation (push) Failing after 9s
CI / YAML lint (push) Failing after 38s
2026-09-29 08:38:48 +02:00
randy 7ee975875a nspanel-patio: right button toggles the relay unless mcu-patio is online
CI / ESPHome config validation (push) Failing after 7s
CI / YAML lint (push) Failing after 38s
2026-09-29 00:03:03 +02:00
randy dd508aec99 m5paper: replace the weather forecast with a calendar (birthdays, waste collection), wake up once a day, IPv6-only 2026-09-28 23:40:13 +02:00
randy e13be73596 m5paper: clear-night icon for sunny hours without UV, center hourly temperature without precipitation 2026-09-28 23:13:31 +02:00
randy b523963944 TFT: switch to LVGL, add XPT2046 touch 2026-09-28 23:13:00 +02:00
randy 6ca813fb64 Pin speaker override (esphome#19862) for stackchan/echo, migrate echo codec option, refresh components hourly 2026-09-28 22:41:08 +02:00
randy d80abdbb90 Add IPv6 WiFi credentials to secrets.yaml.default to fix CI 2026-09-28 22:03:38 +02:00
randy 29b375df68 nspanel: move shared config to common/nspanel.yaml, add TFT version sensor
CI / ESPHome config validation (push) Failing after 7s
CI / YAML lint (push) Failing after 37s
2026-09-28 20:51:05 +02:00
randy 5db5987405 ipv6_only: pin patched lwip so .local names resolve over IPv6 (esp-lwip#94) 2026-09-28 20:12:22 +02:00
randy dec5e5de0a ipv6_only: pin audio override so HTTP reader connects over IPv6 2026-09-28 16:01:28 +02:00
randy 88e1214058 ipv6_only: pin patched espressif/mdns to stop advertising A 0.0.0.0
CI / ESPHome config validation (push) Successful in 10s
CI / YAML lint (push) Failing after 33s
2026-09-28 12:49:33 +02:00
randy 61032ad248 ipv6_only: switch to network enable_ipv4: false (renamed in esphome#19750) 2026-09-28 12:42:17 +02:00
randy 148c51c4df mcu-lvgl-4848s040: add Guition ESP32-S3-4848S040 initial config
CI / ESPHome config validation (push) Failing after 6s
CI / YAML lint (push) Failing after 37s
- mipi_rgb GUITION-4848S040 model, ST7701S init over SPI (48/47)
- GT911 touch mirrored like the image, backlight on GPIO38
- clock and status pages (status until Home Assistant connects),
  same navigation bar as the other LVGL displays
- IPv6-only network
2026-09-27 23:13:33 +02:00
randy cc2ab4c467 Move more devices to the IPv6-only network
Add common/ipv6_only.yaml to mcu-clock-1, mcu-desk-lamp, mcu-dimmer,
mcu-fireplace, mcu-gate, mcu-heater, mcu-kitchen, mcu-mains-power,
mcu-nspanel-office-r, mcu-office-r, mcu-patio, mcu-pow-dishwasher,
mcu-rf, mcu-shed, mcu-well.
2026-09-27 22:51:47 +02:00
randy 504aa06d10 mcu-lvgl, mcu-lvgl-trainer: status page, colored status lines
mcu-lvgl (CYD 4.3"):
- normalized: rpi_dpi_rgb -> mipi_rgb (ESP32-8048S050 pins/timing, pclk
  12.5 MHz), GT911 touch added, platformio_options and default CPU
  frequency dropped, demo meters and duplicate uptime sensors removed
- pages: clock, status (logo, WiFi, IPv6 first, HA, version, uptime);
  status page shown until Home Assistant connects
- same navigation bar and theme as mcu-lvgl-trainer

mcu-lvgl-trainer:
- status lines colored like on the other displays (connected green,
  waiting orange, details gray), stacked in a flex column
- stopwatch format warning fixed
2026-09-27 22:51:47 +02:00
randy 4b6544adfa mcu-tft: status screen until Home Assistant connects
Same boot screen as on the other displays: "Made for ESPHome" logo,
name, WiFi with signal, IPv6 addresses first (link-local skipped),
Home Assistant state, ESPHome version and uptime.
2026-09-27 21:26:07 +02:00
randy 6a51099789 common: ipv6_only package for the IPv6-only IoT network
- common/wifi.yaml: the network gets id wifi_iot, so devices can
  override it with '!extend wifi_iot'
- common/ipv6_only.yaml: add-on package next to any common package;
  switches to the IPv6-only SSID, wifi ipv6_only (SLAAC, no DHCPv4,
  esphome/esphome#19750 as external component until merged) and
  min_ipv6_addr_count: 1
- mcu-lvgl-trainer, mcu-nspanel-dev, mcu-rfid-reader, mcu-stackchan,
  mcu-tft moved to the IPv6-only network
2026-09-27 21:26:02 +02:00
randy 369578a63a mcu-nspanel-office-j: dim the display at night like the bedroom panel
CI / ESPHome config validation (push) Failing after 8s
CI / YAML lint (push) Failing after 38s
Inactive display dim follows the sun (5 % by day, off after dusk at
-6 degrees) and stays at 5 % while light.office_j_lights is on.
Re-applied on time sync, at dawn/dusk and when the lights change.
2026-09-27 20:36:59 +02:00
randy bdf49db1c2 mcu-lvgl-trainer: six pages for the pain cave, fix touch rotation
- touch: drop calibration/transform, the driver defaults to the native
  320x480 panel and LVGL rotates touch points itself (taps were rotated
  by 90 degrees)
- pages: clock (default), basement lights with brightness and color
  temperature for the exercise room (sliders hidden while it is off),
  training start/stop, fan off/50-100 %, stopwatch, status screen with
  "Made for ESPHome" logo and IPv6 first
- light attributes read as text, 'None' while off is skipped
- unused fonts, colors and leftovers removed; ext_uart kept for a
  future ANT+ bridge
2026-09-27 20:31:37 +02:00
randy 349f699572 mcu-stackchan: "Made for ESPHome" logo, IPv6 on status screen
- status screen logo replaced by the official "Made for ESPHome" badge,
  the plain ESPHome logo is not meant for third-party devices
- status screen shows one global IPv6 and one IPv4 address (link-local
  skipped) instead of the IPv4 sensor value
2026-09-27 19:49:57 +02:00
randy 329830e553 mcu-m5paper: rework on M5Stack components, battery mode with forecast
Rewrite of the old config on the core ESPHome components (it8951, gt911,
bm8563, sht3xd):
- USB: always on, forecast screen redrawn every 15 min, forecast
  refreshed every hour and when Home Assistant connects
- battery: BM8563 timer wakes the board every 15 min (off 1:00-5:00),
  it draws the stored forecast and cuts power; WiFi only when the
  forecast is older than 6 h
- mode detected by trying to power off; battery voltage drop on USB
  triggers the battery cycle
- hourly forecast via weather.get_forecasts, 48 h kept in the FM24C02
  EEPROM (include/m5paper_weather.h)
- OTA image confirmed before power-off, battery wake-ups are shorter
  than boot_is_good_after
- status screen with "Made for ESPHome" logo, IPv6 addresses first
2026-09-27 19:49:57 +02:00
randy d813717d2c common: enable ha_time in common packages, devices extend it
Move the homeassistant time platform (id ha_time) into all common
packages. Devices with custom triggers now use '!extend ha_time';
plain duplicate time blocks are removed. mcu-lvgl's unused time_comp
is unified to ha_time.
2026-09-27 16:43:35 +02:00
88 changed files with 3737 additions and 1999 deletions

No files matched your search

+16 -9
View File
@@ -10,35 +10,42 @@ jobs:
name: YAML lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Get changed YAML files
id: changed
uses: tj-actions/changed-files@v46
uses: tj-actions/changed-files@v47
with:
files: "**/*.yaml"
- uses: ibiqlik/action-yamllint@v3
# yamllint straight from pip: Gitea's runner image doesn't ship it like GitHub's does
- name: Lint changed YAML files
if: steps.changed.outputs.any_changed == 'true'
with:
config_file: .yamllint.yml
file_or_dir: ${{ steps.changed.outputs.all_changed_files }}
env:
PIP_BREAK_SYSTEM_PACKAGES: "1"
run: |
pip install --ignore-installed yamllint
yamllint -c .yamllint.yml -f parsable ${{ steps.changed.outputs.all_changed_files }}
validate:
name: ESPHome config validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Get changed device configs
id: changed
uses: tj-actions/changed-files@v46
uses: tj-actions/changed-files@v47
with:
files: "mcu-*.yaml"
- name: Install ESPHome (dev)
if: steps.changed.outputs.any_changed == 'true'
run: pip install git+https://github.com/esphome/esphome.git@dev
# Gitea's runner image marks the system Python as externally managed (PEP 668)
# and has Debian packages pip can't uninstall (pyparsing), so don't touch them
env:
PIP_BREAK_SYSTEM_PACKAGES: "1"
run: pip install --ignore-installed git+https://github.com/esphome/esphome.git@dev
- name: Prepare secrets
if: steps.changed.outputs.any_changed == 'true'
+1 -1
View File
@@ -2,7 +2,7 @@
# This is an example and may include too much for your use-case.
# You can modify this file to suit your needs.
/.claude/
/.esphome/
.esphome/
/secrets.yaml
/archive/
/trash/
+4
View File
@@ -25,3 +25,7 @@ rules:
comments:
require-starting-space: false
# Aligned values (e.g. the bedroom lamp presets) are intentional
colons:
max-spaces-after: -1
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1194" height="240" fill="none" viewBox="0 0 1194 240"><g clip-path="url(#clip0_2_63)"><path fill="#18BCF2" d="M240 219C240 227.24 233.24 234 225 234H15C6.76 234 0 227.24 0 219V129C0 120.76 4.78 109.22 10.6 103.4L109.4 4.61999C115.24 -1.22001 124.78 -1.22001 130.62 4.61999L229.4 103.4C235.24 109.24 240 120.76 240 129V219Z"/><path fill="#F2F4F9" d="M160 78.66H80C76.68 78.66 74 81.34 74 84.66V234H86V90.66H154V102.66H104C100.68 102.66 98 105.34 98 108.66V132.66C98 135.98 100.68 138.66 104 138.66H154V150.66H104C100.68 150.66 98 153.34 98 156.66V180.66C98 183.98 100.68 186.66 104 186.66H154V198.66H104C100.68 198.66 98 201.34 98 204.66C98 207.98 100.68 210.66 104 210.66H160C163.32 210.66 166 207.98 166 204.66V180.66C166 177.34 163.32 174.66 160 174.66H110V162.66H160C163.32 162.66 166 159.98 166 156.66V132.66C166 129.34 163.32 126.66 160 126.66H110V114.66H160C163.32 114.66 166 111.98 166 108.66V84.66C166 81.34 163.32 78.66 160 78.66Z"/><path fill="#F2F4F9" d="M423 167.61V190.11H336V49.95H423V72.63H359.82V108.91H416.26V130.01H359.82V167.61H423Z"/><path fill="#F2F4F9" d="M491.08 47.41C503.9 47.41 514.54 50.53 523.04 56.79C531.54 63.03 536.76 71.39 538.7 81.83L516.3 87.93C515.04 81.93 512.12 77.31 507.54 74.05C502.94 70.81 497.28 69.17 490.52 69.17C483.26 69.17 477.52 70.91 473.28 74.37C469.02 77.83 466.9 82.45 466.9 88.19C466.9 97.25 472.52 103.13 483.78 105.81L506.66 111.53C518.48 114.59 527.32 119.45 533.2 126.11C539.08 132.77 542.02 140.97 542.02 150.71C542.02 163.21 537.48 173.31 528.42 181.03C519.36 188.75 507.24 192.61 492.04 192.61C478.36 192.61 466.78 189.39 457.36 182.95C448.04 176.27 442.54 167.45 440.86 156.51L463.26 150.69C464.08 156.87 467.16 161.73 472.5 165.23C477.84 168.73 484.64 170.47 492.9 170.47C501.16 170.47 507.08 168.79 511.6 165.45C516.14 162.11 518.4 157.57 518.4 151.81C518.4 142.81 512.78 136.87 501.52 133.99L478.64 128.45C466.88 125.77 458.06 120.99 452.16 114.15C446.26 107.31 443.3 98.95 443.3 89.07C443.3 76.69 447.7 66.65 456.48 58.93C465.26 51.21 476.8 47.35 491.12 47.35L491.08 47.41Z"/><path fill="#F2F4F9" d="M666.1 95.61C666.1 109.37 661.92 120.49 653.58 128.99C645.24 137.49 634 141.75 619.88 141.75H588.38V190.13H564.56V49.95H620.06C634.3 49.95 645.54 54.07 653.76 62.27C661.98 70.49 666.08 81.59 666.08 95.59L666.1 95.61ZM641.16 95.05C641.16 87.99 638.96 82.25 634.56 77.85C630.16 73.45 623.92 71.25 615.86 71.25H588.4V120.85H615.5C623.74 120.85 630.1 118.51 634.54 113.81C638.98 109.13 641.2 102.87 641.2 95.05H641.16Z"/><path fill="#F2F4F9" d="M687.38 49.95H711.2V108.55L772.98 108.73V49.95H796.98V190.11H772.98V129.83L711.2 129.65V190.11H687.38V49.95Z"/><path fill="#F2F4F9" d="M868.6 92.79C883.1 92.79 894.92 97.45 904.04 106.75C913.16 116.07 917.72 128.03 917.72 142.65C917.72 157.27 913.16 169.15 904.04 178.47C894.92 187.79 883.1 192.43 868.6 192.43C854.1 192.43 842.1 187.77 832.98 178.47C823.86 169.15 819.3 157.23 819.3 142.65C819.3 128.07 823.86 115.97 832.98 106.69C842.1 97.41 853.98 92.77 868.6 92.77V92.79ZM868.6 172.01C876.34 172.01 882.64 169.27 887.5 163.81C892.34 158.35 894.76 151.23 894.76 142.49C894.76 133.75 892.34 126.67 887.5 121.25C882.66 115.85 876.36 113.15 868.6 113.15C860.84 113.15 854.26 115.85 849.38 121.25C844.5 126.65 842.06 133.73 842.06 142.49C842.06 151.25 844.5 158.35 849.38 163.81C854.26 169.27 860.66 172.01 868.6 172.01Z"/><path fill="#F2F4F9" d="M1081.6 129.83V190.11H1059.56V133.29C1059.56 126.73 1057.88 121.61 1054.5 117.91C1051.12 114.23 1046.54 112.37 1040.72 112.37C1034.54 112.37 1029.6 114.39 1025.9 118.41C1022.22 122.45 1020.36 128.09 1020.36 135.33V190.09H998.04V133.27C998.04 126.71 996.4 121.59 993.12 117.89C989.84 114.21 985.3 112.35 979.48 112.35C973.3 112.35 968.32 114.37 964.58 118.39C960.84 122.41 958.96 128.07 958.96 135.31V190.07H936.28V95.39H957.38L958.14 104.49C963.64 96.43 972.6 92.39 985.04 92.39C992.28 92.39 998.58 93.89 1003.88 96.89C1009.2 99.89 1013.22 104.27 1015.98 110.01C1018.3 104.51 1022.12 100.19 1027.46 97.07C1032.8 93.95 1039.16 92.39 1046.54 92.39C1057.28 92.39 1065.82 95.71 1072.14 102.33C1078.46 108.95 1081.6 118.11 1081.6 129.79V129.83Z"/><path fill="#F2F4F9" d="M1193.54 151.11H1120.98C1121.74 158.23 1124.42 163.67 1129.04 167.43C1133.66 171.19 1139.54 173.05 1146.66 173.05C1158.22 173.05 1166.32 168.23 1170.94 158.61L1189.88 166.11C1186.32 174.43 1180.7 180.93 1173.06 185.61C1165.4 190.29 1156.6 192.65 1146.66 192.65C1132.66 192.65 1121.3 188.07 1112.58 178.91C1103.86 169.75 1099.5 157.73 1099.5 142.87C1099.5 128.01 1103.9 115.91 1112.68 106.59C1121.46 97.27 1132.94 92.63 1147.14 92.63C1161.34 92.63 1172.3 97.23 1180.8 106.41C1189.3 115.59 1193.56 127.69 1193.56 142.69V151.13L1193.54 151.11ZM1121.36 135.17H1170.48C1170.04 127.49 1167.72 121.63 1163.5 117.59C1159.28 113.55 1153.6 111.55 1146.48 111.55C1139.36 111.55 1133.66 113.59 1129.24 117.69C1124.8 121.79 1122.18 127.61 1121.36 135.17Z"/></g><defs><clipPath id="clip0_2_63"><rect width="1193.56" height="240" fill="#fff"/></cliLine truncated

Before

Width:  |  Height:  |  Size: 4.9 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_2" data-name="Layer 2" viewBox="0 0 681.98 201.98"><defs><style>.cls-1{fill:none;stroke:#1d2126;stroke-miterlimit:10;stroke-width:1.01px}.cls-2{fill:#1d2126}.cls-2,.cls-3,.cls-4{stroke-width:0}.cls-3{fill:#f2f4f9}.cls-4{fill:#18bcf2}</style></defs><g id="Layer_1-2" data-name="Layer 1"><g><g><rect width="680.97" height="200.97" x=".51" y=".51" class="cls-3" rx="40.48" ry="40.48"/><rect width="680.97" height="200.97" x=".51" y=".51" class="cls-1" rx="40.48" ry="40.48"/></g><g><path d="M236.13,43.11v26.53h-5.29v-14.5l-5.68,14.5h-5.08l-5.61-14.4v14.4h-5.12v-26.53h5.12l8.16,20.27,8.21-20.27h5.29Z" class="cls-4"/><path d="M259.54,63.84h-9.04l-2.02,5.8h-5.59l9.51-26.53h5.33l9.47,26.53h-5.7l-1.97-5.8ZM258,59.34l-2.95-8.7-2.99,8.7h5.94Z" class="cls-4"/><path d="M296.93,56.42c.02,1.89-.3,3.66-.98,5.31s-1.61,3.06-2.8,4.22-2.61,2.07-4.26,2.73-3.4.98-5.26.96h-9.65v-26.53h9.65c2.43-.04,4.66.52,6.71,1.68s3.67,2.76,4.86,4.82,1.78,4.33,1.74,6.81ZM291.25,56.42c0-2.46-.71-4.46-2.12-5.99s-3.27-2.29-5.58-2.29h-4.22v16.52h4.22c2.34,0,4.21-.75,5.61-2.26s2.09-3.5,2.09-5.99Z" class="cls-4"/><path d="M321.38,64.59v5.04h-16.7v-26.53h16.7v5.1h-11.34v5.66h10.07v4.75h-10.07v5.98h11.34Z" class="cls-4"/><path d="M348.35,48.17v6.1h9.58l-.04,4.82h-9.54v10.55h-5.36v-26.53h16.73l-.04,5.06h-11.34Z" class="cls-4"/><path d="M378.62,42.64c1.9,0,3.66.34,5.27,1.03s2.99,1.63,4.11,2.84,2,2.66,2.63,4.35.94,3.52.94,5.49c.02,1.95-.28,3.77-.91,5.48s-1.52,3.17-2.65,4.39-2.52,2.17-4.15,2.86-3.39,1.03-5.27,1c-2.5.04-4.74-.54-6.72-1.72s-3.52-2.82-4.6-4.92-1.6-4.45-1.56-7.05c-.02-1.95.28-3.77.91-5.48s1.51-3.18,2.65-4.39,2.51-2.17,4.13-2.87,3.37-1.03,5.23-1ZM378.65,64.82c2.24,0,4.01-.76,5.32-2.28s1.96-3.58,1.96-6.2-.65-4.71-1.95-6.22-3.08-2.27-5.33-2.27-4.03.76-5.33,2.27-1.95,3.59-1.95,6.22.65,4.71,1.95,6.21,3.08,2.26,5.33,2.26Z" class="cls-4"/><path d="M419.5,69.64h-6.01l-4.08-9.58h-4.89v9.58h-5.36v-26.53h10.21c3.28.01,5.76.74,7.44,2.19s2.51,3.55,2.51,6.3c0,1.79-.39,3.34-1.17,4.65s-1.89,2.28-3.33,2.91l4.68,10.48ZM413.63,51.6c0-1.15-.36-2.05-1.07-2.72s-1.78-.99-3.18-.99h-4.85v7.49h4.85c1.41,0,2.47-.34,3.18-1.01s1.07-1.6,1.07-2.77Z" class="cls-4"/></g><g><path d="M251.92,146.83v11.25h-43.5v-70.08h43.5v11.34h-31.59v18.14h28.22v10.55h-28.22v18.8h31.59Z" class="cls-2"/><path d="M285,86.74c6.41,0,11.73,1.56,15.98,4.69,4.25,3.12,6.86,7.3,7.83,12.52l-11.2,3.05c-.62-3-2.09-5.31-4.38-6.94-2.3-1.62-5.13-2.44-8.51-2.44-3.62,0-6.5.87-8.62,2.6s-3.19,4.04-3.19,6.91c0,4.53,2.81,7.47,8.44,8.81l11.44,2.86c5.91,1.53,10.33,3.96,13.27,7.29s4.41,7.43,4.41,12.3c0,6.25-2.27,11.3-6.8,15.16-4.53,3.86-10.59,5.79-18.19,5.79-6.84,0-12.62-1.61-17.34-4.83-4.66-3.34-7.41-7.75-8.25-13.22l11.2-2.91c.41,3.09,1.95,5.52,4.62,7.27,2.67,1.75,6.07,2.62,10.2,2.62s7.09-.84,9.35-2.51c2.27-1.67,3.4-3.94,3.4-6.82,0-4.5-2.81-7.47-8.44-8.91l-11.44-2.77c-5.88-1.34-10.29-3.73-13.24-7.15s-4.43-7.6-4.43-12.54c0-6.19,2.2-11.21,6.59-15.07,4.39-3.86,10.16-5.79,17.32-5.79Z" class="cls-2"/><path d="M371.55,110.83c0,6.88-2.09,12.44-6.26,16.69-4.17,4.25-9.79,6.38-16.85,6.38h-15.75v24.19h-11.91v-70.08h27.75c7.12,0,12.74,2.06,16.85,6.16,4.11,4.11,6.16,9.66,6.16,16.66ZM359.08,110.55c0-3.53-1.1-6.4-3.3-8.6s-5.32-3.3-9.35-3.3h-13.73v24.8h13.55c4.12,0,7.3-1.17,9.52-3.52s3.33-5.47,3.33-9.38Z" class="cls-2"/><path d="M381.23,88h11.91v29.3l30.89.09v-29.39h12v70.08h-12v-30.14l-30.89-.09v30.23h-11.91v-70.08Z" class="cls-2"/><path d="M470.88,109.43c7.25,0,13.16,2.33,17.72,6.98,4.56,4.66,6.84,10.64,6.84,17.95s-2.28,13.25-6.84,17.91c-4.56,4.66-10.47,6.98-17.72,6.98s-13.25-2.33-17.81-6.98c-4.56-4.66-6.84-10.62-6.84-17.91s2.28-13.34,6.84-17.98,10.5-6.96,17.81-6.96ZM470.88,149.04c3.88,0,7.02-1.37,9.45-4.1,2.42-2.73,3.63-6.29,3.63-10.66s-1.21-7.91-3.63-10.62c-2.42-2.7-5.57-4.05-9.45-4.05s-7.17,1.35-9.61,4.05c-2.44,2.7-3.66,6.24-3.66,10.62s1.22,7.93,3.66,10.66c2.44,2.73,5.64,4.1,9.61,4.1Z" class="cls-2"/><path d="M576.42,127.94v30.14h-11.02v-28.41c0-3.28-.84-5.84-2.53-7.69-1.69-1.84-3.98-2.77-6.89-2.77-3.09,0-5.56,1.01-7.41,3.02s-2.77,4.84-2.77,8.46v27.38h-11.16v-28.41c0-3.28-.82-5.84-2.46-7.69-1.64-1.84-3.91-2.77-6.82-2.77-3.09,0-5.58,1.01-7.45,3.02s-2.81,4.84-2.81,8.46v27.38h-11.34v-47.34h10.55l.38,4.55c2.75-4.03,7.23-6.05,13.45-6.05,3.62,0,6.77.75,9.42,2.25s4.67,3.69,6.05,6.56c1.16-2.75,3.07-4.91,5.74-6.47,2.67-1.56,5.85-2.34,9.54-2.34,5.38,0,9.64,1.66,12.8,4.97,3.16,3.31,4.73,7.89,4.73,13.73Z" class="cls-2"/><path d="M631.43,138.58h-36.28c.38,3.56,1.72,6.28,4.03,8.16s5.25,2.81,8.81,2.81c5.78,0,9.83-2.41,12.14-7.22l9.47,3.75c-1.78,4.16-4.59,7.41-8.41,9.75s-8.23,3.52-13.2,3.52c-7,0-12.68-2.29-17.04-6.87-4.36-4.58-6.54-10.59-6.54-18.02s2.2-13.48,6.59-18.14c4.39-4.66,10.13-6.98,17.23-6.98s12.58,2.3,16.83,6.89,6.38,10.64,6.38,18.14v4.22ZM595.34,130.61h24.56c-.22-3.84-1.38-6.77-3.49-8.79s-4.95-3.02-8.51-3.02-6.41,1.02-8.62,3.07c-2.22,2.05-3.53,4.96-3.94,8.74Z" class="cls-2"/></g><g><path d="M170.55,153.49c0,4.12-3.38,7.5-7.5,7.5H58.05c-4.12,0-7.5-3.38-7.5-7.5v-45c0-4.12,2.39-9.89,5.3-12Line truncated

After

Width:  |  Height:  |  Size: 5.3 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_2" data-name="Layer 2" viewBox="0 0 681.98 201.98"><defs><style>.cls-1{fill:#1d2126}.cls-1,.cls-2,.cls-3{stroke-width:0}.cls-2{fill:#f2f4f9}.cls-3{fill:#18bcf2}.cls-4{fill:none;stroke:#f2f4f9;stroke-miterlimit:10;stroke-width:1.01px}</style></defs><g id="Layer_1-2" data-name="Layer 1"><g><g><rect width="680.97" height="200.97" x=".51" y=".51" class="cls-1" rx="40.48" ry="40.48"/><rect width="680.97" height="200.97" x=".51" y=".51" class="cls-4" rx="40.48" ry="40.48"/></g><g><path d="M236.13,43.11v26.53h-5.29v-14.5l-5.68,14.5h-5.08l-5.61-14.4v14.4h-5.12v-26.53h5.12l8.16,20.27,8.21-20.27h5.29Z" class="cls-3"/><path d="M259.54,63.84h-9.04l-2.02,5.8h-5.59l9.51-26.53h5.33l9.47,26.53h-5.7l-1.97-5.8ZM258,59.34l-2.95-8.7-2.99,8.7h5.94Z" class="cls-3"/><path d="M296.93,56.42c.02,1.89-.3,3.66-.98,5.31s-1.61,3.06-2.8,4.22-2.61,2.07-4.26,2.73-3.4.98-5.26.96h-9.65v-26.53h9.65c2.43-.04,4.66.52,6.71,1.68s3.67,2.76,4.86,4.82,1.78,4.33,1.74,6.81ZM291.25,56.42c0-2.46-.71-4.46-2.12-5.99s-3.27-2.29-5.58-2.29h-4.22v16.52h4.22c2.34,0,4.21-.75,5.61-2.26s2.09-3.5,2.09-5.99Z" class="cls-3"/><path d="M321.38,64.59v5.04h-16.7v-26.53h16.7v5.1h-11.34v5.66h10.07v4.75h-10.07v5.98h11.34Z" class="cls-3"/><path d="M348.35,48.17v6.1h9.58l-.04,4.82h-9.54v10.55h-5.36v-26.53h16.73l-.04,5.06h-11.34Z" class="cls-3"/><path d="M378.62,42.64c1.9,0,3.66.34,5.27,1.03s2.99,1.63,4.11,2.84,2,2.66,2.63,4.35.94,3.52.94,5.49c.02,1.95-.28,3.77-.91,5.48s-1.52,3.17-2.65,4.39-2.52,2.17-4.15,2.86-3.39,1.03-5.27,1c-2.5.04-4.74-.54-6.72-1.72s-3.52-2.82-4.6-4.92-1.6-4.45-1.56-7.05c-.02-1.95.28-3.77.91-5.48s1.51-3.18,2.65-4.39,2.51-2.17,4.13-2.87,3.37-1.03,5.23-1ZM378.65,64.82c2.24,0,4.01-.76,5.32-2.28s1.96-3.58,1.96-6.2-.65-4.71-1.95-6.22-3.08-2.27-5.33-2.27-4.03.76-5.33,2.27-1.95,3.59-1.95,6.22.65,4.71,1.95,6.21,3.08,2.26,5.33,2.26Z" class="cls-3"/><path d="M419.5,69.64h-6.01l-4.08-9.58h-4.89v9.58h-5.36v-26.53h10.21c3.28.01,5.76.74,7.44,2.19s2.51,3.55,2.51,6.3c0,1.79-.39,3.34-1.17,4.65s-1.89,2.28-3.33,2.91l4.68,10.48ZM413.63,51.6c0-1.15-.36-2.05-1.07-2.72s-1.78-.99-3.18-.99h-4.85v7.49h4.85c1.41,0,2.47-.34,3.18-1.01s1.07-1.6,1.07-2.77Z" class="cls-3"/></g><g><path d="M251.92,146.83v11.25h-43.5v-70.08h43.5v11.34h-31.59v18.14h28.22v10.55h-28.22v18.8h31.59Z" class="cls-2"/><path d="M285,86.74c6.41,0,11.73,1.56,15.98,4.69,4.25,3.12,6.86,7.3,7.83,12.52l-11.2,3.05c-.62-3-2.09-5.31-4.38-6.94-2.3-1.62-5.13-2.44-8.51-2.44-3.62,0-6.5.87-8.62,2.6s-3.19,4.04-3.19,6.91c0,4.53,2.81,7.47,8.44,8.81l11.44,2.86c5.91,1.53,10.33,3.96,13.27,7.29s4.41,7.43,4.41,12.3c0,6.25-2.27,11.3-6.8,15.16-4.53,3.86-10.59,5.79-18.19,5.79-6.84,0-12.62-1.61-17.34-4.83-4.66-3.34-7.41-7.75-8.25-13.22l11.2-2.91c.41,3.09,1.95,5.52,4.62,7.27,2.67,1.75,6.07,2.62,10.2,2.62s7.09-.84,9.35-2.51c2.27-1.67,3.4-3.94,3.4-6.82,0-4.5-2.81-7.47-8.44-8.91l-11.44-2.77c-5.88-1.34-10.29-3.73-13.24-7.15s-4.43-7.6-4.43-12.54c0-6.19,2.2-11.21,6.59-15.07,4.39-3.86,10.16-5.79,17.32-5.79Z" class="cls-2"/><path d="M371.55,110.83c0,6.88-2.09,12.44-6.26,16.69-4.17,4.25-9.79,6.38-16.85,6.38h-15.75v24.19h-11.91v-70.08h27.75c7.12,0,12.74,2.06,16.85,6.16,4.11,4.11,6.16,9.66,6.16,16.66ZM359.08,110.55c0-3.53-1.1-6.4-3.3-8.6s-5.32-3.3-9.35-3.3h-13.73v24.8h13.55c4.12,0,7.3-1.17,9.52-3.52s3.33-5.47,3.33-9.38Z" class="cls-2"/><path d="M381.23,88h11.91v29.3l30.89.09v-29.39h12v70.08h-12v-30.14l-30.89-.09v30.23h-11.91v-70.08Z" class="cls-2"/><path d="M470.88,109.43c7.25,0,13.16,2.33,17.72,6.98,4.56,4.66,6.84,10.64,6.84,17.95s-2.28,13.25-6.84,17.91c-4.56,4.66-10.47,6.98-17.72,6.98s-13.25-2.33-17.81-6.98c-4.56-4.66-6.84-10.62-6.84-17.91s2.28-13.34,6.84-17.98,10.5-6.96,17.81-6.96ZM470.88,149.04c3.88,0,7.02-1.37,9.45-4.1,2.42-2.73,3.63-6.29,3.63-10.66s-1.21-7.91-3.63-10.62c-2.42-2.7-5.57-4.05-9.45-4.05s-7.17,1.35-9.61,4.05c-2.44,2.7-3.66,6.24-3.66,10.62s1.22,7.93,3.66,10.66c2.44,2.73,5.64,4.1,9.61,4.1Z" class="cls-2"/><path d="M576.42,127.94v30.14h-11.02v-28.41c0-3.28-.84-5.84-2.53-7.69-1.69-1.84-3.98-2.77-6.89-2.77-3.09,0-5.56,1.01-7.41,3.02s-2.77,4.84-2.77,8.46v27.38h-11.16v-28.41c0-3.28-.82-5.84-2.46-7.69-1.64-1.84-3.91-2.77-6.82-2.77-3.09,0-5.58,1.01-7.45,3.02s-2.81,4.84-2.81,8.46v27.38h-11.34v-47.34h10.55l.38,4.55c2.75-4.03,7.23-6.05,13.45-6.05,3.62,0,6.77.75,9.42,2.25s4.67,3.69,6.05,6.56c1.16-2.75,3.07-4.91,5.74-6.47,2.67-1.56,5.85-2.34,9.54-2.34,5.38,0,9.64,1.66,12.8,4.97,3.16,3.31,4.73,7.89,4.73,13.73Z" class="cls-2"/><path d="M631.43,138.58h-36.28c.38,3.56,1.72,6.28,4.03,8.16s5.25,2.81,8.81,2.81c5.78,0,9.83-2.41,12.14-7.22l9.47,3.75c-1.78,4.16-4.59,7.41-8.41,9.75s-8.23,3.52-13.2,3.52c-7,0-12.68-2.29-17.04-6.87-4.36-4.58-6.54-10.59-6.54-18.02s2.2-13.48,6.59-18.14c4.39-4.66,10.13-6.98,17.23-6.98s12.58,2.3,16.83,6.89,6.38,10.64,6.38,18.14v4.22ZM595.34,130.61h24.56c-.22-3.84-1.38-6.77-3.49-8.79s-4.95-3.02-8.51-3.02-6.41,1.02-8.62,3.07c-2.22,2.05-3.53,4.96-3.94,8.74Z" class="cls-2"/></g><g><path d="M170.55,153.49c0,4.12-3.38,7.5-7.5,7.5H58.05c-4.12,0-7.5-3.38-7.5-7.5v-45c0-4.12,2.39-9.89,5.3-12Line truncated

After

Width:  |  Height:  |  Size: 5.3 KiB

Submodule common/.esphome/external_components/b7dc7eea deleted from 16571e8a90.
+2 -2
View File
@@ -24,8 +24,8 @@ text_sensor:
# - <<: !include text_sensor/uptime.yaml
- <<: !include text_sensor/wifi_info.yaml
# time:
#. - <<: !include time/homeassistant.yaml
time:
- <<: !include time/homeassistant.yaml
network:
enable_ipv6: true
+4 -1
View File
@@ -24,5 +24,8 @@ text_sensor:
- <<: !include text_sensor/version.yaml
- <<: !include text_sensor/wifi_info.yaml
time:
- <<: !include time/homeassistant.yaml
network:
enable_ipv6: true
enable_ipv6: true
+4 -1
View File
@@ -23,5 +23,8 @@ text_sensor:
- <<: !include text_sensor/version.yaml
- <<: !include text_sensor/wifi_info.yaml
time:
- <<: !include time/homeassistant.yaml
network:
enable_ipv6: true
enable_ipv6: true
+3
View File
@@ -21,5 +21,8 @@ text_sensor:
- <<: !include text_sensor/version.yaml
- <<: !include text_sensor/ethernet_info.yaml
time:
- <<: !include time/homeassistant.yaml
network:
enable_ipv6: true
+3
View File
@@ -27,3 +27,6 @@ text_sensor:
- <<: !include text_sensor/git_ref.yaml
- <<: !include text_sensor/version.yaml
- <<: !include text_sensor/wifi_info.yaml
time:
- <<: !include time/homeassistant.yaml
+34
View File
@@ -0,0 +1,34 @@
---
# IPv6-only IoT network (SLAAC, no DHCPv4); add next to a common package:
# packages:
# common: !include common/common.yaml
# ipv6_only: !include common/ipv6_only.yaml
external_components:
# network enable_ipv4 + audio HTTP reader over IPv6 (esphome/esphome#19750), drop once merged
- source: github://pr#19750
components: [const, network, wifi, audio]
wifi:
networks:
- id: !extend wifi_iot
ssid: !secret wifi_ssid_ipv6
password: !secret wifi_password_ipv6
esp32:
framework:
components:
# mdns 1.12.0 + fix for "A 0.0.0.0" without IPv4 (espressif/esp-protocols PR pending), drop once released
- name: espressif/mdns
source: https://github.com/randybb/esp-protocols.git
ref: mdns-v1.12.0-zero-ipv4-test
path: components/mdns
# IDF v5.5.5 lwip + .local resolution over IPv6 (espressif/esp-lwip#94), drop once in IDF
- name: lwip
source: https://github.com/randybb/esp-lwip.git
ref: idf-v5.5.5-lwip-component
path: lwip
network:
enable_ipv6: true
enable_ipv4: false
min_ipv6_addr_count: 1
+166
View File
@@ -0,0 +1,166 @@
---
# Sonoff NSPanel with the native Lovelace UI (randybb/esphome-nspanel-lovelace-native).
# The device file adds the cards, buttons and relays:
# packages:
# common: !include common/common.yaml
# nspanel: !include
# file: common/nspanel.yaml
# vars:
# temperature_entity: sensor.zigbee_bedroom_temperature
# nspanel_lovelace:
# cards: [...]
defaults:
temperature_name: Temperature
ntc_reference_temperature: 25°C
esphome:
on_boot:
then:
- switch.turn_off: screen_power
- delay: 1s
- switch.turn_on: screen_power
- delay: 2s
- lambda: 'id(nspanel_id).set_display_dim(5, 80);'
esp32:
variant: esp32
toolchain: esp-idf
framework:
type: esp-idf
advanced:
flash_chip: generic
minimum_chip_revision: 3.0
sram1_as_iram: true
packages:
popup: !include nspanel_popup.yaml
external_components:
- source:
type: git
url: https://github.com/randybb/esphome-nspanel-lovelace-native
ref: devices
refresh: 0s
components: [nspanel_lovelace]
api:
homeassistant_services: true
homeassistant_states: true
actions:
- action: play_rtttl
variables:
song: string
then:
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify
variables:
heading: string
message: string
song: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(heading, message, 10000);'
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify_fullscreen
variables:
title: string
description: string
button1: string
button2: string
timeout: int
icon: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(title, description, timeout);'
- rtttl.play: "scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b"
uart:
id: display_uart
tx_pin: 16
rx_pin: 17
baud_rate: 115200
nspanel_lovelace:
id: nspanel_id
sleep_timeout: 10
experimental_vertical_ui: true
locale:
language: sk
temperature_unit: celcius
screensaver:
time_id: ha_time
time_format: '%H:%M'
date_format: '%A, %d. %b. %Y'
weather:
entity_id: sensor.weather_forecast_daily
icon_color: [255, 255, 255]
entities:
- entity_id: ${temperature_entity}
icon:
value: home-thermometer-outline
color: [255, 255, 255]
precision: 1
output:
- platform: ledc
id: buzzer_out
pin:
number: 21
switch:
- platform: gpio
name: Screen Power
id: screen_power
entity_category: config
pin:
number: 4
inverted: true
restore_mode: ALWAYS_ON
rtttl:
id: buzzer
output: buzzer_out
sensor:
- platform: adc
id: ntc_source
pin: 38
update_interval: 5min
attenuation: 12db
- platform: resistance
id: resistance_sensor
sensor: ntc_source
configuration: DOWNSTREAM
resistor: 11.2kOhm
- platform: ntc
name: ${temperature_name}
id: temperature
sensor: resistance_sensor
calibration:
b_constant: 3950
reference_temperature: ${ntc_reference_temperature}
reference_resistance: 10kOhm
text_sensor:
- platform: homeassistant
id: name_day
entity_id: sensor.nameday_sk
on_value:
- lambda: |-
id(nspanel_id).set_time_format("%H:%M~" + x);
id(nspanel_id).update_time();
# HMI protocol version reported by the TFT on startup (52/53 for this UI)
- platform: template
name: TFT Version
entity_category: diagnostic
update_interval: 60s
lambda: |-
using esphome::nspanel_lovelace::Configuration;
const auto ver = Configuration::get_version();
if (ver == 0) return {"unknown"};
return {std::to_string(ver) + " (" + Configuration::get_model_str() + ")"};
+98
View File
@@ -0,0 +1,98 @@
---
# NSPanel popups (popupNotify page), without changes to nspanel_lovelace:
# - OTA progress
# - device info (version, IPs) via the show_info API action
# Needs nspanel_lovelace (id nspanel_id), its uart (id display_uart) and the
# ota id ota_esphome (common/ota_esp32.yaml).
# The component doesn't track these popups; the panel either reboots (OTA)
# or goes back to the default page afterwards.
api:
actions:
- action: show_info
then:
- script.execute: info_popup
script:
- id: info_popup
mode: restart
then:
- lambda: |-
char build[Application::BUILD_TIME_STR_SIZE];
App.get_build_time_string(build);
std::string msg = "ESPHome " ESPHOME_VERSION "\r\n";
msg += build;
// global/ULA first, link-local last
std::vector<std::string> ips;
for (int pass = 0; pass < 2; pass++) {
for (auto &ip : wifi::global_wifi_component->wifi_sta_ip_addresses()) {
if (!ip.is_set()) continue;
char buf[network::IP_ADDRESS_BUFFER_SIZE];
ip.str_to(buf);
bool ll = strncmp(buf, "fe80", 4) == 0;
if (ll == (pass == 1)) ips.emplace_back(buf);
}
}
for (auto &ip : ips) msg += "\r\n" + ip;
id(nspanel_id).send_display_command("pageType~popupNotify");
id(nspanel_id).send_display_command(
"entityUpdateDetail~info~" + App.get_friendly_name() + "~65535~~65535~~65535~" + msg + "~65535~15");
- delay: 15s
- lambda: 'id(nspanel_id).render_default_page();'
# OTA blocks the main loop, and nspanel_lovelace only sends its queued
# commands from loop(), so these frames go straight to the uart in the
# component's format: 55 BB, length (LE), command, CRC16 (LE).
- id: ota_popup
parameters:
message: string
then:
- lambda: |-
auto send = [](const std::string &cmd) {
uint8_t hdr[4] = {0x55, 0xBB, uint8_t(cmd.size() & 0xFF), uint8_t(cmd.size() >> 8)};
uint16_t crc = crc16(hdr, 4);
crc = crc16(reinterpret_cast<const uint8_t *>(cmd.data()), cmd.size(), crc);
uint8_t tail[2] = {uint8_t(crc & 0xFF), uint8_t(crc >> 8)};
id(display_uart).write_array(hdr, 4);
id(display_uart).write_array(reinterpret_cast<const uint8_t *>(cmd.data()), cmd.size());
id(display_uart).write_array(tail, 2);
id(display_uart).flush();
};
send("dimmode~100~100");
send("pageType~popupNotify");
send("entityUpdateDetail~ota~Aktualizácia firmvéru~65535~~65535~~65535~" + message + "~65535~0");
ota:
- id: !extend ota_esphome
on_begin:
- script.execute:
id: ota_popup
message: Nahrávam…
on_progress:
- lambda: |-
static int last = -1;
int pct = (int) x / 10 * 10;
if (pct != last) {
last = pct;
id(ota_popup)->execute("Nahrávam… " + std::to_string(pct) + " %");
}
on_end:
- script.execute:
id: ota_popup
message: Hotovo, reštartujem
on_error:
- script.execute:
id: ota_popup
message: Aktualizácia zlyhala
- delay: 5s
- lambda: |-
id(nspanel_id).set_display_dim(5, 80);
id(nspanel_id).render_default_page();
button:
# put button.<device>_info on a card: the panel presses it through HA
- platform: template
name: Info
id: info_button
entity_category: diagnostic
on_press:
- script.execute: info_popup
+42
View File
@@ -0,0 +1,42 @@
---
# NSPanel screensaver dims to 0 at night (sun below -6°), unless the room lights are on.
# packages:
# sleep_dim: !include
# file: common/nspanel_sleep_dim.yaml
# vars:
# sleep_override_entity: light.bedroom_lights
script:
- id: apply_sleep_dim
then:
- lambda: |-
uint8_t dim;
if (id(sleep_override).state) dim = 5; // sleepOverride
else if (id(sun_id).is_above_horizon(-6)) dim = 5; // day
else dim = 0; // night
id(nspanel_id).set_display_inactive_dim(dim);
time:
- id: !extend ha_time
on_time_sync:
- script.execute: apply_sleep_dim
binary_sensor:
- platform: homeassistant # sleepOverride
id: sleep_override
entity_id: ${sleep_override_entity}
on_state:
- script.execute: apply_sleep_dim
sun:
id: sun_id
time_id: ha_time
latitude: 48.15°
longitude: 17.11°
on_sunrise:
- elevation: -6°
then:
- script.execute: apply_sleep_dim
on_sunset:
- elevation: -6°
then:
- script.execute: apply_sleep_dim
+4
View File
@@ -2,3 +2,7 @@
ota:
- platform: esphome
password: !secret ota_password
# migration to encrypted OTA (api key): once every device encrypts,
# remove allow_plaintext_upload together with the password
encryption:
allow_plaintext_upload: true
+5
View File
@@ -1,5 +1,10 @@
---
ota:
- platform: esphome
id: ota_esphome
password: !secret ota_password
# migration to encrypted OTA (api key): once every device encrypts,
# remove allow_plaintext_upload together with the password
encryption:
allow_plaintext_upload: true
allow_partition_access: true
-1
View File
@@ -7,4 +7,3 @@ accuracy_decimals: 2
update_interval: 60s
filters:
- lambda: return x / 86400;
+127
View File
@@ -0,0 +1,127 @@
---
# Status on a visible RGB light, which stays a normal light otherwise:
# network down red, slow blink
# no API client (HA) orange, slow blink
# component error purple, steady (only with show_errors: "true", for a dedicated status LED)
# OTA blue, fast blink; green when done, 3 red blinks on error
# back to normal green for 1 s, then the light goes back to how it was
# packages:
# status_led: !include
# file: common/status_led.yaml
# vars:
# light_id: led_light
# Needs the ota id ota_esphome (common/ota_esp32.yaml).
defaults:
brightness: "0.3"
show_errors: "false" # a failed component would take over a display or a shared light for good
globals:
- id: status_led_active
type: bool
initial_value: "false"
- id: status_led_saved
type: light::LightColorValues
- id: status_led_last
type: uint32_t
initial_value: "0xFFFFFFFF"
script:
- id: status_led_show
parameters:
r: float
g: float
b: float
lit: bool
then:
- lambda: |-
auto *l = id(${light_id});
uint32_t key = (lit << 24) | (uint32_t(r * 255) << 16) | (uint32_t(g * 255) << 8) | uint32_t(b * 255);
if (!id(status_led_active)) {
id(status_led_saved) = l->remote_values;
id(status_led_active) = true;
} else if (key == id(status_led_last)) {
return; // unchanged: don't flood Home Assistant with the same state
}
id(status_led_last) = key;
if (lit) {
l->turn_on().set_rgb(r, g, b).set_brightness(${brightness}).set_transition_length(0).set_effect("None").perform();
} else {
l->turn_off().set_transition_length(0).perform();
}
l->loop(); // write now: OTA blocks the main loop
- id: status_led_restore
parameters:
confirm: bool
then:
- lambda: |-
if (id(status_led_active) && confirm) id(status_led_show)->execute(0.0f, 1.0f, 0.0f, true);
- if:
condition:
lambda: 'return id(status_led_active) && confirm;'
then:
- delay: 1s # green: back to normal
- lambda: |-
if (!id(status_led_active)) return;
id(status_led_active) = false;
id(status_led_last) = 0xFFFFFFFF;
id(${light_id})->make_call().from_light_color_values(id(status_led_saved)).set_transition_length(0).perform();
interval:
- interval: 500ms
then:
- lambda: |-
static uint8_t tick = 0;
tick++;
bool slow = (tick / 2) % 2 == 0; // 1 s on, 1 s off
bool error = ${show_errors} && (App.get_app_state() & STATUS_LED_ERROR);
bool problem = !network::is_connected() || !api::global_api_server->is_connected() || error;
if (problem) id(status_led_restore)->stop();
if (!network::is_connected()) {
id(status_led_show)->execute(1.0f, 0.0f, 0.0f, slow);
} else if (!api::global_api_server->is_connected()) {
id(status_led_show)->execute(1.0f, 0.4f, 0.0f, slow);
} else if (error) {
id(status_led_show)->execute(0.6f, 0.0f, 1.0f, true);
} else if (id(status_led_active) && !id(status_led_restore)->is_running()) {
id(status_led_restore)->execute(true);
}
ota:
- id: !extend ota_esphome
on_begin:
- script.execute:
id: status_led_show
r: 0.0
g: 0.0
b: 1.0
lit: true
on_progress:
- lambda: 'id(status_led_show)->execute(0.0f, 0.0f, 1.0f, (millis() / 250) % 2 == 0);'
on_end:
- script.execute:
id: status_led_show
r: 0.0
g: 1.0
b: 0.0
lit: true
on_error:
- repeat:
count: 3
then:
- script.execute:
id: status_led_show
r: 1.0
g: 0.0
b: 0.0
lit: true
- delay: 250ms
- script.execute:
id: status_led_show
r: 1.0
g: 0.0
b: 0.0
lit: false
- delay: 250ms
- script.execute:
id: status_led_restore
confirm: false
+19
View File
@@ -0,0 +1,19 @@
---
# Status LED on the M5Stack ATOM Lite's own RGB LED (G27), see common/status_led.yaml
packages:
status_led: !include
file: status_led.yaml
vars:
light_id: atom_led
show_errors: "true" # dedicated status LED
light:
- platform: esp32_rmt_led_strip
id: atom_led
internal: true
pin: 27
num_leds: 1
rmt_symbols: 64 # 1 LED is 24 bits; leave RMT memory for remote_transmitter/receiver
chipset: ws2812
channel_colors: GRB
restore_mode: ALWAYS_OFF
+1 -1
View File
@@ -5,4 +5,4 @@ id: git_ref_sensor
long: true
all: true
abbrev: 16
dirty: "-dirty"
dirty: "-dirty"
+2
View File
@@ -2,6 +2,8 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd # ESP32-PICO-D4, like every other ATOM Lite
type: esp-idf
external_components:
+3 -1
View File
@@ -2,7 +2,9 @@
wifi:
# reboot_timeout: 0s
networks:
- ssid: !secret wifi_ssid
# id lets devices override the network with '!extend wifi_iot'
- id: wifi_iot
ssid: !secret wifi_ssid
password: !secret wifi_password
enable_btm: true
enable_rrm: true
+1 -1
View File
@@ -7,4 +7,4 @@ wifi:
# enable_rrm: true
ap:
ssid: TEST
password: testtest
password: testtest
+160
View File
@@ -0,0 +1,160 @@
#pragma once
// Upcoming calendar events for mcu-m5paper: parsed from the calendar.get_events
// response and kept in flash (NVS), so they survive the power-off between RTC wake-ups.
#include <algorithm>
#include <cstdio>
#include <cstring>
#include "esphome/components/json/json_util.h"
#include "esphome/core/preferences.h"
#include "esphome/core/time.h"
namespace m5paper_calendar {
static constexpr uint8_t MAX_EVENTS = 32;
static constexpr size_t SUMMARY_LEN = 44;
static constexpr uint16_t ALL_DAY = 0xFFFF;
static constexpr uint32_t PREF_HASH = 0x6D35C41A;
enum Kind : uint8_t { BIRTHDAY = 0, WASTE };
struct Event {
uint16_t day; // local date, days since 1970-01-01
uint16_t minute; // local start time in minutes after midnight, ALL_DAY if none
uint8_t kind;
char summary[SUMMARY_LEN + 1];
};
struct Events {
uint32_t fetched_at{0}; // UTC epoch of the download
uint8_t count{0};
Event items[MAX_EVENTS]{};
bool valid() const { return this->fetched_at != 0; }
};
// the events in RAM, loaded from flash at boot
inline Events &events() {
static Events ev;
return ev;
}
// days since 1970-01-01 for a proleptic Gregorian date (H. Hinnant's algorithm)
inline int32_t days_from_civil(int y, int m, int d) {
y -= m <= 2;
const int era = (y >= 0 ? y : y - 399) / 400;
const int yoe = y - era * 400;
const int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
const int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
return era * 146097 + doe - 719468;
}
inline int32_t local_day(const esphome::ESPTime &t) { return days_from_civil(t.year, t.month, t.day_of_month); }
// 0 = Monday
inline int weekday(int32_t day) { return (day + 3) % 7; }
// "2026-10-01" (all-day) or "2026-10-01T10:00:00+02:00" -> local day and minute; false on error
inline bool parse_start(const char *s, uint16_t &day, uint16_t &minute) {
int y, mo, d, h, mi, sec = 0, oh = 0, om = 0;
char sign = '+';
int n = sscanf(s, "%d-%d-%dT%d:%d:%d%c%d:%d", &y, &mo, &d, &h, &mi, &sec, &sign, &oh, &om);
if (n < 3)
return false;
if (n < 5) {
day = days_from_civil(y, mo, d);
minute = ALL_DAY;
return true;
}
int64_t ts = int64_t(days_from_civil(y, mo, d)) * 86400 + h * 3600 + mi * 60 + sec;
if (n >= 8 && (sign == '+' || sign == '-')) {
int64_t offset = oh * 3600 + om * 60;
ts += sign == '+' ? -offset : offset;
}
if (ts <= 0)
return false;
const auto t = esphome::ESPTime::from_epoch_local(ts);
day = local_day(t);
minute = t.hour * 60 + t.minute;
return true;
}
// copy at most SUMMARY_LEN bytes without cutting a UTF-8 sequence
inline void copy_summary(char *dst, const char *src) {
size_t n = strnlen(src, SUMMARY_LEN + 1);
if (n > SUMMARY_LEN) {
n = SUMMARY_LEN;
while (n > 0 && (uint8_t(src[n]) & 0xC0) == 0x80)
n--;
}
memcpy(dst, src, n);
dst[n] = '\0';
}
// Parse the calendar.get_events response; Home Assistant wraps the action response as
// {"response": {"calendar.x": {"events": [...]}, ...}}; every calendar other than the waste one holds birthdays
inline bool parse(ArduinoJson::JsonObjectConst response, const char *waste, uint32_t now, Events &ev) {
ArduinoJson::JsonObjectConst root = response["response"].is<ArduinoJson::JsonObjectConst>()
? response["response"].as<ArduinoJson::JsonObjectConst>()
: response;
if (root.size() == 0)
return false;
Events out;
for (ArduinoJson::JsonPairConst cal : root) {
const uint8_t kind = strcmp(cal.key().c_str(), waste) == 0 ? WASTE : BIRTHDAY;
for (ArduinoJson::JsonObjectConst item : cal.value()["events"].as<ArduinoJson::JsonArrayConst>()) {
Event e;
if (!parse_start(item["start"] | "", e.day, e.minute))
continue;
e.kind = kind;
copy_summary(e.summary, item["summary"] | "");
// the same birthday in the contacts and the manual calendar
if (std::any_of(out.items, out.items + out.count,
[&e](const Event &o) { return o.day == e.day && strcmp(o.summary, e.summary) == 0; }))
continue;
if (out.count < MAX_EVENTS) {
out.items[out.count++] = e;
continue;
}
// full: keep the nearest events
Event *last = std::max_element(out.items, out.items + out.count,
[](const Event &a, const Event &b) { return a.day < b.day; });
if (e.day < last->day)
*last = e;
}
}
std::sort(out.items, out.items + out.count, [](const Event &a, const Event &b) {
// all-day (0xFFFF wraps to 0) first
return a.day != b.day ? a.day < b.day : uint16_t(a.minute + 1) < uint16_t(b.minute + 1);
});
out.fetched_at = now;
ev = out;
return true;
}
// battery cycle: refreshed once a day, after midnight
inline bool stale(const esphome::ESPTime &now) {
const auto &ev = events();
return !ev.valid() || !now.is_valid() || now.timestamp - ev.fetched_at >= 20 * 3600;
}
inline esphome::ESPPreferenceObject &pref() {
static esphome::ESPPreferenceObject p = esphome::global_preferences->make_preference<Events>(PREF_HASH, true);
return p;
}
inline bool load(Events &ev) {
if (!pref().load(&ev)) {
ev = Events{};
return false;
}
ev.count = std::min(ev.count, MAX_EVENTS);
return true;
}
// written to flash right away: the board may power off before the next preferences flush
inline bool save(const Events &ev) { return pref().save(&ev) && esphome::global_preferences->sync(); }
} // namespace m5paper_calendar
+17 -10
View File
@@ -1,4 +1,12 @@
---
# Hardware: IKEA VINDRIKTNING (modded) + M5Stack M5Stamp Pico
# Pinout:
# GPIO21 PM1006 UART -> particle_uart (uart tx_pin)
# GPIO22 PM1006 UART -> particle_uart (uart rx_pin)
# GPIO25 TZT 8-bit WS2812 5050 stick (8 LEDs, 7 visible outside) -> NEO [neo] (light esp32_rmt_led_strip), also status
# GPIO27 Onboard RGB LED (1x WS2812, inside), unused
# GPIO32 Grove SDA -> i2c (i2c sda)
# GPIO33 Grove SCL -> i2c (i2c scl)
substitutions:
device: air-office-r
name: Office R Air
@@ -16,10 +24,16 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
status_led: !include
file: common/status_led.yaml
vars:
light_id: neo
i2c:
# - id: i2c0
@@ -46,20 +60,13 @@ uart:
# inverted: true
light:
- platform: esp32_rmt_led_strip
# name: LED
id: neo
channel_colors: GRB
pin: 27
num_leds: 1
chipset: ws2812
restore_mode: ALWAYS_OFF
# also the status light (common/status_led.yaml): back to its previous state when all is fine
- platform: esp32_rmt_led_strip
name: NEO
id: neo_strip
id: neo
channel_colors: GRB
pin: 25
num_leds: 7
num_leds: 7 # 8 on the stick, the 8th one is hidden
chipset: ws2812
restore_mode: ALWAYS_OFF
effects:
+13 -1
View File
@@ -1,4 +1,14 @@
---
# Hardware: Apollo Automation ESK-1 ESPHome Starter Kit
# Pinout:
# GPIO0 -> i2c_1 (i2c scl)
# GPIO1 -> i2c_1 (i2c sda)
# GPIO4 -> Accessory Power (switch gpio)
# GPIO5 -> Onboard RGB LED (light esp32_rmt_led_strip)
# GPIO14 -> RGB LEDs (light esp32_rmt_led_strip)
# GPIO18 -> buzzer_output (output ledc)
# I2C:
# 0x38 aht20 (sensor aht10)
substitutions:
device: apollo-dev #test
name: Apollo DEV #test
@@ -16,6 +26,8 @@ esp32:
flash_size: 8MB
toolchain: esp-idf
framework:
advanced:
flash_chip: generic
type: esp-idf
packages:
@@ -30,7 +42,7 @@ api:
then:
- rtttl.play:
rtttl: !lambda 'return song;'
switch:
- platform: gpio
id: accessory_power
+60 -5
View File
@@ -1,4 +1,23 @@
---
# Hardware: M5Stack AtomS3
# Pinout:
# GPIO1 Grove SCL -> motor_in1 (output gpio)
# GPIO2 Grove SDA -> motor_in2 (output gpio)
# GPIO5 -> canbus/esp32_can (canbus esp32_can tx_pin)
# GPIO6 -> canbus/esp32_can (canbus esp32_can rx_pin)
# GPIO15 -> display_tft (display mipi_spi cs_pin)
# GPIO16 -> gpio_tft_backlight (output ledc)
# GPIO17 -> spi (spi clk_pin)
# GPIO21 -> spi (spi mosi_pin)
# GPIO33 -> display_tft (display mipi_spi dc_pin)
# GPIO34 -> display_tft (display mipi_spi reset_pin)
# GPIO38 -> i2c_main (i2c sda)
# GPIO39 -> i2c_main (i2c scl)
# GPIO41 -> Button (binary_sensor gpio) (inverted)
# I2C:
# 0x21 pcf8574_hub (pcf8574)
# 0x26 m5stack_relay_1 (m5stack_4relay)
# 0x3C lcd (display ssd1306_i2c)
substitutions:
device: atoms3
name: AtomS3
@@ -23,6 +42,8 @@ esp32:
flash_size: 8MB
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
ota:
@@ -33,12 +54,14 @@ pcf8574:
address: 0x21
pcf8575: true
animation:
- file: "assets/images/blinky.gif"
image:
- platform: animation
file: "assets/images/blinky.gif"
id: blinky
resize: 128x128
type: RGB565
- file: "assets/images/vault_boy_walking.gif"
- platform: animation
file: "assets/images/vault_boy_walking.gif"
id: vaultboy
resize: 168x121
type: RGB565
@@ -108,6 +131,11 @@ external_components:
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include
file: common/status_led.yaml
vars:
light_id: status_frame
# common: !include common/common_wo_debug.yaml
# common: !include common/common_dev.yaml
@@ -211,12 +239,32 @@ output:
- platform: ledc
pin: 16
id: gpio_tft_backlight
# virtual RGB light for common/status_led.yaml, shown full screen on the display
- platform: template
id: status_frame_r
type: float
write_action: []
- platform: template
id: status_frame_g
type: float
write_action: []
- platform: template
id: status_frame_b
type: float
write_action: []
light:
- platform: monochromatic
id: display_tft_backlight
output: gpio_tft_backlight
restore_mode: ALWAYS_ON
- platform: rgb
id: status_frame
internal: true
red: status_frame_r
green: status_frame_g
blue: status_frame_b
restore_mode: ALWAYS_OFF
switch:
- platform: template
@@ -372,6 +420,7 @@ display:
- platform: mipi_spi
model: ST7789V
id: display_tft
byte_order: little_endian # colours were byte-swapped (purple showed as green)
dimensions:
height: 128
width: 128
@@ -384,11 +433,18 @@ display:
# eightbitcolor: true
update_interval: 1s
lambda: |-
// status screen (common/status_led.yaml): the whole display in the status colour
auto &sv = id(status_frame)->current_values;
if (sv.is_on()) {
it.fill(Color(sv.get_red() * 255, sv.get_green() * 255, sv.get_blue() * 255));
return;
}
//Ingress shown animation Frame.
id(blinky).next_frame();
// Draw the animation my_animation at position [x=0,y=0]
it.image(0, 0, id(blinky), COLOR_ON, COLOR_OFF);
// // it.print(0, 0, id(font_default), "Hello World!");
// // it.strftime(0, 0, id(font_default), TextAlign::TOP_LEFT, "%H:%M", id(ha_time).now());
// it.rectangle(0, 0, it.get_width(), it.get_height(), id(my_blue));
@@ -491,8 +547,7 @@ sensor:
# name: Dallas Temp 4
# one_wire_id: hub_1
time:
- !include common/time/homeassistant.yaml
# time:
# - platform: sntp
# id: sntp_time
# timezone: Europe/Bratislava
+8 -8
View File
@@ -1,4 +1,12 @@
---
# Hardware: Sonoff Dual R2
# Pinout:
# GPIO0 Pin "button 0" on expansion header
# GPIO5 Relay #2 and green color on LED -> relay_2 (output gpio)
# GPIO9 Pin "button 1" on expansion header
# GPIO10 Push Button
# GPIO12 Relay #1 and red color on LED -> relay_1 (output gpio)
# GPIO13 Blue Status LED -> status_led (status_led) (inverted)
substitutions:
device: basement-2
name_short: Basement
@@ -18,14 +26,6 @@ esp8266:
packages:
common: !include common/common_esp8266.yaml
# Sonoff Dual R2
# GPIO10 Push Button
# GPIO00 Pin "button 0" on expansion header
# GPIO09 Pin "button 1" on expansion header
# GPIO12 Relay #1 and red color on LED
# GPIO05 Relay #2 and green color on LED
# GPIO13 Blue Status LED
status_led:
pin:
number: 13
+9 -11
View File
@@ -1,4 +1,12 @@
---
# Hardware: Sonoff Dual R2
# Pinout:
# GPIO0 Pin "button 0" on expansion header -> Light Switch (binary_sensor gpio) (inverted)
# GPIO5 Relay #2 and green color on LED -> Socket 1 (switch gpio)
# GPIO9 Pin "button 1" on expansion header -> Door (binary_sensor gpio) (inverted)
# GPIO10 Push Button -> Socket 1 Switch (binary_sensor gpio) (inverted)
# GPIO12 Relay #1 and red color on LED -> Sewage Treatment Aerator Pump [relay_1] (switch gpio)
# GPIO13 Blue Status LED -> status_led (status_led) (inverted)
substitutions:
device: basement
name: Basement
@@ -17,15 +25,6 @@ esp8266:
packages:
common: !include common/common_esp8266.yaml
# Sonoff Dual R2
# Pin Function
# GPIO10 Push Button
# GPIO00 Pin "button 0" on expansion header
# GPIO09 Pin "button 1" on expansion header
# GPIO12 Relay #1 and red color on LED
# GPIO05 Relay #2 and green color on LED
# GPIO13 Blue Status LED
globals:
- id: aerator_auto
type: bool
@@ -139,8 +138,7 @@ switch:
id: relay_2
time:
- platform: homeassistant
timezone: Europe/Bratislava
- id: !extend ha_time
on_time:
- seconds: 0
minutes: /15
+24 -10
View File
@@ -1,4 +1,23 @@
---
# Hardware: Xiaomi Mi Bedside Lamp 2 (ESP-WROOM-32D, single core; RGBW LEDs)
# Pinout (github.com/mmakaay/esphome-xiaomi_bslamp2, doc/technical_details.md):
# GPIO1 Debug pad TX
# GPIO2 Debug pad, free I/O
# GPIO3 Debug pad RX
# GPIO4 LEDs master switch 2
# GPIO5 LEDs blue PWM
# GPIO12 LEDs white PWM
# GPIO13 LEDs red PWM
# GPIO14 LEDs green PWM
# GPIO16 Front panel interrupt
# GPIO17 EEPROM I2C SDA
# GPIO18 EEPROM I2C SCL
# GPIO19 Front panel I2C SCL -> front_panel_i2c (i2c scl)
# GPIO21 Front panel I2C SDA -> front_panel_i2c (i2c sda)
# GPIO33 LEDs master switch 1
# I2C:
# 0x10 EEPROM-like IC on its own bus (GPIO17/18), not configured
# 0x2C Front panel
substitutions:
device: bedroom-lamp-left
name: Bedroom Lamp Left
@@ -20,26 +39,21 @@ esp32:
sdkconfig_options:
CONFIG_FREERTOS_UNICORE: y
advanced:
flash_chip: generic
ignore_efuse_custom_mac: true
ignore_efuse_mac_crc: true
external_components:
- source:
type: git
url: https://github.com/mmakaay/esphome-xiaomi_bslamp2
ref: dev
# fork: fix for ESPHome 2026.10 (restore_mode -> restore_state), back to mmakaay once merged
url: https://github.com/randybb/esphome-xiaomi_bslamp2
ref: fix-light-restore-state
refresh: 1h
packages:
common: !include common/common.yaml
# Mi Desk Lamp
# Pin Function (Name)
# GPIO02: Button (GPIO_KEY1)
# GPIO04: Cold White (GPIO_PWM1)
# GPIO05: Warm White (GPIO_PWM2)
# GPIO12: Rotary switch A pin (GPIO_ROT_A)
# GPIO13: Rotary switch B pin (GPIO_ROT_B)
ipv6_only: !include common/ipv6_only.yaml
# ------------------------------------------------------------------------
# Behavior: default
+24 -10
View File
@@ -1,4 +1,23 @@
---
# Hardware: Xiaomi Mi Bedside Lamp 2 (ESP-WROOM-32D, single core; RGBW LEDs)
# Pinout (github.com/mmakaay/esphome-xiaomi_bslamp2, doc/technical_details.md):
# GPIO1 Debug pad TX
# GPIO2 Debug pad, free I/O
# GPIO3 Debug pad RX
# GPIO4 LEDs master switch 2
# GPIO5 LEDs blue PWM
# GPIO12 LEDs white PWM
# GPIO13 LEDs red PWM
# GPIO14 LEDs green PWM
# GPIO16 Front panel interrupt
# GPIO17 EEPROM I2C SDA
# GPIO18 EEPROM I2C SCL
# GPIO19 Front panel I2C SCL -> front_panel_i2c (i2c scl)
# GPIO21 Front panel I2C SDA -> front_panel_i2c (i2c sda)
# GPIO33 LEDs master switch 1
# I2C:
# 0x10 EEPROM-like IC on its own bus (GPIO17/18), not configured
# 0x2C Front panel
substitutions:
device: bedroom-lamp-right
name: Bedroom Lamp Right
@@ -20,26 +39,21 @@ esp32:
sdkconfig_options:
CONFIG_FREERTOS_UNICORE: y
advanced:
flash_chip: generic
ignore_efuse_custom_mac: true
ignore_efuse_mac_crc: true
external_components:
- source:
type: git
url: https://github.com/mmakaay/esphome-xiaomi_bslamp2
ref: dev
# fork: fix for ESPHome 2026.10 (restore_mode -> restore_state), back to mmakaay once merged
url: https://github.com/randybb/esphome-xiaomi_bslamp2
ref: fix-light-restore-state
refresh: 60s
packages:
common: !include common/common.yaml
# Mi Desk Lamp
# Pin Function (Name)
# GPIO02: Button (GPIO_KEY1)
# GPIO04: Cold White (GPIO_PWM1)
# GPIO05: Warm White (GPIO_PWM2)
# GPIO12: Rotary switch A pin (GPIO_ROT_A)
# GPIO13: Rotary switch B pin (GPIO_ROT_B)
ipv6_only: !include common/ipv6_only.yaml
# ------------------------------------------------------------------------
# Behavior: default
+3
View File
@@ -1,4 +1,7 @@
---
# Hardware: Espressif ESP32-C6-DevKitC-1
# Pinout:
# GPIO8 -> LED (light esp32_rmt_led_strip)
substitutions:
device: c6-test-1
name: C6 TEST 1
+3
View File
@@ -1,4 +1,7 @@
---
# Hardware: Espressif ESP32-C6-DevKitC-1
# Pinout:
# GPIO8 -> LED (light esp32_rmt_led_strip)
substitutions:
device: c6-test-2
name: C6 TEST 2
+17
View File
@@ -1,4 +1,21 @@
---
# Hardware: ESP32-CAM (AI-Thinker style, runs hot)
# Pinout:
# GPIO0 -> Camera (esp32_camera)
# GPIO5 -> Camera (esp32_camera data_pins)
# GPIO18 -> Camera (esp32_camera data_pins)
# GPIO19 -> Camera (esp32_camera data_pins)
# GPIO21 -> Camera (esp32_camera data_pins)
# GPIO22 -> Camera (esp32_camera pixel_clock_pin)
# GPIO23 -> Camera (esp32_camera href_pin)
# GPIO25 -> Camera (esp32_camera vsync_pin)
# GPIO26 -> i2c_bus (i2c sda)
# GPIO27 -> i2c_bus (i2c scl)
# GPIO32 -> Enable (switch gpio)
# GPIO34 -> Camera (esp32_camera data_pins)
# GPIO35 -> Camera (esp32_camera data_pins)
# GPIO36 -> Camera (esp32_camera data_pins)
# GPIO39 -> Camera (esp32_camera data_pins)
substitutions:
device: cam-1
name: Cam 1
+6
View File
@@ -1,4 +1,10 @@
---
# Hardware: ESP32 DevKit
# Pinout:
# GPIO0 -> Boot (binary_sensor gpio) (inverted)
# GPIO2 -> LED (switch gpio)
# GPIO22 -> can_bus (canbus esp32_can rx_pin)
# GPIO23 -> can_bus (canbus esp32_can tx_pin)
substitutions:
device: can-node-1
name: CAN Node 1
+9
View File
@@ -1,4 +1,13 @@
---
# Hardware: ESP32 DevKit
# Pinout:
# GPIO17 -> i2c (i2c sda)
# GPIO18 -> i2c (i2c scl)
# GPIO19 -> as3935_i2c (as3935_i2c irq_pin)
# GPIO22 -> can_bus (canbus esp32_can rx_pin)
# GPIO23 -> can_bus (canbus esp32_can tx_pin)
# I2C:
# 0x03 as3935_i2c (as3935_i2c)
substitutions:
device: can-node-2
name: CAN Node 2
+11 -5
View File
@@ -1,4 +1,13 @@
---
# Hardware: M5Stack M5Stamp Pico
# Pinout:
# GPIO22 -> uart_distance (uart rx_pin)
# GPIO25 -> uart_distance (uart tx_pin)
# GPIO26 -> hdmi_cec (hdmi_cec)
# GPIO27 -> LED (light esp32_rmt_led_strip)
# GPIO32 Grove SDA -> i2c (i2c sda)
# GPIO33 Grove SCL -> i2c (i2c scl)
# GPIO39 -> Bedroom TV Button (binary_sensor gpio) (inverted)
substitutions:
device: cec-bedroom
name: Bedroom TV
@@ -15,6 +24,8 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd # ESP32-PICO-D4, like the other M5Stamp Pico (not read from the device)
type: esp-idf
external_components:
@@ -31,11 +42,6 @@ packages:
debug:
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
i2c:
# - id: i2c0
sda: 32
+17 -20
View File
@@ -1,4 +1,18 @@
---
# Hardware: M5Stack M5Stamp C3
# Pinout:
# GPIO0 I2C SCL
# GPIO1 I2C SDA, BUTTON
# GPIO2 RGB
# GPIO4 DISPLAY CLOCK -> tm1637_display (display tm1637 clk_pin)
# GPIO5 DISPLAY DIO -> tm1637_display (display tm1637 dio_pin)
# GPIO6 GPIO
# GPIO7 GPIO
# GPIO8 GPIO
# GPIO9 GPIO (BUZZER?) -> rtttl_out (output ledc)
# GPIO10 GPIO
# GPIO20 UART RX
# GPIO21 UART TX
substitutions:
device: clock-1
name: Clock 1
@@ -17,27 +31,15 @@ esp32:
variant: esp32c3
toolchain: esp-idf
framework:
advanced:
flash_chip: generic
type: esp-idf
# version: 5.4.2
# platform_version: 54.03.21
packages:
common: !include common/common.yaml
# GPIO21 UART TX
# GPIO20 UART RX
# GPIO0 I2C SCL
# GPIO1 I2C SDA
# GPIO2 RGB
# GPIO1 BUTTON
# GPIO4 DISPLAY CLOCK
# GPIO5 DISPLAY DIO
# GPIO6 GPIO
# GPIO7 GPIO
# GPIO8 GPIO
# GPIO10 GPIO
#
# GPIO9 GPIO (BUZZER?)
ipv6_only: !include common/ipv6_only.yaml
# https://github.com/granadaxronos/120-SONG_NOKIA_RTTTL_RINGTONE_PLAYER_FOR_ARDUINO_UNO/blob/master/RTTTL_PLAYER/songs.h
api:
@@ -109,11 +111,6 @@ globals:
restore_value: no
initial_value: "false"
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
display:
- platform: tm1637
id: tm1637_display
+11 -5
View File
@@ -1,4 +1,13 @@
---
# Hardware: M5Stack M5Stamp Pico
# Pinout:
# GPIO25 -> rtttl_out (output ledc)
# GPIO27 -> LED (light esp32_rmt_led_strip)
# GPIO32 Grove SDA -> i2c_main (i2c sda)
# GPIO33 Grove SCL -> i2c_main (i2c scl)
# GPIO39 -> Button (binary_sensor gpio) (inverted)
# I2C:
# 0x24 tm1650_display (display tm1650)
substitutions:
device: clock-living-room
name: Living room Clock
@@ -15,6 +24,8 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd # ESP32-PICO-D4, like the other M5Stamp Pico (not read from the device)
type: esp-idf
external_components:
@@ -51,11 +62,6 @@ globals:
restore_value: no
initial_value: "false"
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
binary_sensor:
- platform: gpio
name: Button
+10 -8
View File
@@ -1,4 +1,11 @@
---
# Hardware: Xiaomi Mi Desk Lamp, brain transplant: M5Stack M5Stamp Pico (originally ESP8266)
# Pinout:
# GPIO18 Warm White (GPIO_PWM2) -> warm_white (output ledc)
# GPIO19 Cold White (GPIO_PWM1) -> cold_white (output ledc)
# GPIO21 Rotary switch A pin (GPIO_ROT_A) -> rotary (sensor rotary_encoder pin_a)
# GPIO26 Rotary switch B pin (GPIO_ROT_B) -> rotary (sensor rotary_encoder pin_b)
# GPIO36 Button (GPIO_KEY1) -> rotary_button (binary_sensor gpio) (inverted)
substitutions:
device: desk-lamp
name: Desk Lamp
@@ -15,18 +22,13 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
# Mi Desk Lamp
# Pin Function (Name)
# GPIO18: Warm White (GPIO_PWM2)
# GPIO19: Cold White (GPIO_PWM1)
# GPIO21: Rotary switch A pin (GPIO_ROT_A)
# GPIO26: Rotary switch B pin (GPIO_ROT_B)
# GPIO36: Button (GPIO_KEY1)
ipv6_only: !include common/ipv6_only.yaml
binary_sensor:
+10
View File
@@ -1,4 +1,11 @@
---
# Hardware: M5Stack M5Stamp Pico
# Pinout:
# GPIO22 -> dimmer1 (output ac_dimmer gate_pin)
# GPIO25 -> dimmer1 (output ac_dimmer zero_cross_pin) (inverted)
# GPIO27 -> LED (light esp32_rmt_led_strip)
# GPIO32 Grove SDA
# GPIO33 Grove SCL
substitutions:
device: dimmer
name: Dimmer
@@ -30,10 +37,13 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# fan:
# - platform: speed
+17
View File
@@ -1,4 +1,14 @@
---
# Hardware: M5Stack ATOM Echo
# Pinout:
# GPIO19 -> speaker_bus (i2s_audio i2s_bclk_pin)
# GPIO22 -> speaker_id (speaker i2s_audio i2s_dout_pin)
# GPIO23 -> echo_microphone (microphone i2s_audio i2s_din_pin)
# GPIO26 Grove SDA
# GPIO27 ATOM RGB LED -> LED [neo_buildin] (light esp32_rmt_led_strip), also status
# GPIO32 Grove SCL
# GPIO33 -> speaker_bus (i2s_audio i2s_lrclk_pin)
# GPIO39 -> Button (binary_sensor gpio) (inverted)
substitutions:
device: echo-1
name: Echo 1
@@ -15,10 +25,17 @@ esphome:
esp32:
variant: esp32
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include
file: common/status_led.yaml
vars:
light_id: neo_buildin
api:
actions:
+22 -11
View File
@@ -1,4 +1,16 @@
---
# Hardware: Xiaomi Mijia Gateway, brain transplant: M5Stack ATOM Echo (kept the speaker, LEDs and PSU)
# Pinout:
# GPIO12 -> Button (binary_sensor gpio) (inverted)
# GPIO19 -> speaker_bus (i2s_audio i2s_bclk_pin)
# GPIO21 Gateway LED ring red -> led_red (output ledc)
# GPIO22 -> speaker_id (speaker i2s_audio i2s_dout_pin)
# GPIO23 Gateway LED ring blue -> led_blue (output ledc)
# GPIO25 Gateway LED ring green -> led_green (output ledc)
# GPIO26 Grove SDA -> i2c (i2c sda)
# GPIO27 ATOM onboard RGB LED (inside, not visible)
# GPIO32 Grove SCL -> i2c (i2c scl)
# GPIO33 -> speaker_bus (i2s_audio i2s_lrclk_pin)
substitutions:
device: echo
name: Echo
@@ -16,10 +28,17 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include
file: common/status_led.yaml
vars:
light_id: led_light
api:
actions:
@@ -71,11 +90,6 @@ light:
red: led_red
green: led_green
blue: led_blue
- platform: status_led
id: led_status
pin:
number: 23
allow_other_uses: true
output:
- platform: ledc
@@ -86,9 +100,7 @@ output:
pin: 25
- platform: ledc
id: led_blue
pin:
number: 23
allow_other_uses: true
pin: 23
i2s_audio:
- id: speaker_bus
@@ -127,16 +139,15 @@ media_player:
- platform: speaker
id: media_out
name: Player
codec_support_enabled: false
buffer_size: 14000
media_pipeline:
speaker: media_spk_resampling_input
# format: WAV
format: WAV # only the WAV decoder is built (was codec_support_enabled: false)
# num_channels: 1
# sample_rate: 8000 # Lower sample rate
announcement_pipeline:
speaker: announcement_spk_resampling_input
# format: WAV
format: WAV
# num_channels: 1
# sample_rate: 8000 # Lower sample rate
on_play:
+18 -22
View File
@@ -1,4 +1,22 @@
---
# Hardware: M5Stack M5Stamp C3
# Pinout:
# GPIO0 I2C SCL -> i2c_grove (i2c scl)
# GPIO1 I2C SDA, BUTTON -> i2c_grove (i2c sda)
# GPIO2 RGB
# GPIO4 GPIO
# GPIO5 GPIO
# GPIO6 GPIO
# GPIO7 GPIO
# GPIO8 GPIO
# GPIO9 GPIO
# GPIO10 GPIO
# GPIO18 UART RX -> uart_hdmi_switch (uart rx_pin)
# GPIO19 UART TX -> uart_hdmi_switch (uart tx_pin)
# GPIO20 UART RX, LOGGER -> uart_log (uart rx_pin)
# GPIO21 UART TX, LOGGER -> uart_log (uart tx_pin)
# I2C:
# 0x20 pcf8574_hub (pcf8574)
substitutions:
device: eworkbench
name: Electronics Workbench
@@ -22,23 +40,6 @@ esp32:
packages:
common: !include common/common.yaml
# GPIO20 UART RX, LOGGER
# GPIO21 UART TX, LOGGER
# GPIO9 GPIO
#
# GPIO0 I2C SCL
# GPIO1 I2C SDA
# GPIO2 RGB
# GPIO1 BUTTON
# GPIO4 GPIO
# GPIO5 GPIO
# GPIO6 GPIO
# GPIO7 GPIO
# GPIO8 GPIO
# GPIO10 GPIO
# GPIO18 UART RX
# GPIO19 UART TX
i2c:
- id: i2c_grove
sda: 1
@@ -242,11 +243,6 @@ binary_sensor:
# on_clockwise:
# - display_menu.down:
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
# display:
# - platform: tm1637
# id: tm1637_display
+22 -20
View File
@@ -1,4 +1,22 @@
---
# Hardware: M5Stack ATOM Lite + ATOM Hub Switch
# Pinout:
# GPIO1 UART0 TX
# GPIO3 UART0 RX
# GPIO12 IR
# GPIO19 Relay2
# GPIO21 I2C1 SCL -> i2c (i2c scl)
# GPIO22 Relay1
# GPIO23 RS485 Tx
# GPIO25 I2C1 SDA - red -> i2c (i2c sda)
# GPIO26 I2C0 SDA - white
# GPIO27 NEO 1x -> atom_led (status LED, common/status_led_atom.yaml)
# GPIO32 I2C0 SCL
# GPIO33 RS485 Rx
# GPIO39 BUTTON -> Status Button (binary_sensor gpio)
# I2C:
# 0x18 one_wire_bus (one_wire ds2482)
# 0x27 pca9554_module (pca9554)
substitutions:
device: fireplace
name: Heating Fireplace
@@ -15,6 +33,8 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
external_components:
@@ -27,28 +47,10 @@ external_components:
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
# PINOUTS: M5ATOM+Atom Hub Switch
# IR G12
# NEO G27 1x
# BUTTON G39
# I2C0 SDA G26 - white
# I2C0 SCL G32
# I2C1 SDA G25 - red
# I2C1 SCL G21
# UART0 RX G3
# UART0 TX G1
# RS485 Rx G33
# RS485 Tx G23
# Relay1 G22
# Relay2 G19
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
i2c:
# - id: i2c0
# sda: 26
+19 -15
View File
@@ -1,4 +1,19 @@
---
# Hardware: M5Stack ATOM Lite + ATOM Hub Switch
# Pinout:
# GPIO1 UART0 TX
# GPIO3 UART0 RX
# GPIO12 IR
# GPIO19 RELAY-2 -> relay_2 (output gpio)
# GPIO21 I2C1 SCL
# GPIO22 RELAY-1 -> relay_1 (output gpio)
# GPIO23 RS485 TX
# GPIO25 I2C1 SDA red
# GPIO26 I2C0 SDA white
# GPIO27 NEO -> atom_led (status LED, common/status_led_atom.yaml)
# GPIO32 I2C0 SCL -> gate_ogi_state (binary_sensor gpio) (inverted); gate_ogi_blink (binary_sensor gpio) (inverted)
# GPIO33 RS485 RX
# GPIO39 BUTTON
substitutions:
device: gate
name: Gate
@@ -15,25 +30,14 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
# PINOUTS: M5ATOM
# IR G12
# NEO G27
# BUTTON G39
# I2C0 SDA G26 white
# I2C0 SCL G32
# I2C1 SDA G25 red
# I2C1 SCL G21
# UART0 RX G3
# UART0 TX G1
# RS485 RX G33
# RS485 TX G23
# RELAY-1 G22
# RELAY-2 G19
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
button:
- platform: output
+28 -16
View File
@@ -1,4 +1,31 @@
---
# Hardware: Olimex ESP32-POE-ISO
# Pinout:
# # UEXT
# 3V3 1 2 GND
# GPIO4 3 4 GPIO36 U1TXD/U1RXD
# GPIO16 5 6 GPIO13 I2C-SCL/I2C-SDA
# GPIO15 7 8 GPIO2 HS2_CMD/HS2_DATA0
# GPIO14 9 10 GPIO5 HS2_CLK/SPI_CS
#
# SD/MMC; shared with UEXT, no CS!!!
# GPIO15 HS2_CMD
# GPIO14 HS2_CLK
# GPIO2 HS2_DATA0
#
# GPIO34 BUT1
# GPIO35 Battery Measurment ADC
# GPIO39 Ext Power Sense ADC
# Used:
# GPIO4 uart_modbus (uart tx_pin)
# GPIO12 ethernet (ethernet power_pin)
# GPIO13 i2c (i2c sda)
# GPIO16 i2c (i2c scl)
# GPIO17 ethernet (ethernet)
# GPIO18 ethernet (ethernet mdio_pin)
# GPIO23 ethernet (ethernet mdc_pin)
# GPIO34 user_button (binary_sensor gpio) (inverted)
# GPIO36 uart_modbus (uart rx_pin)
substitutions:
device: gateway
name: Gateway
@@ -17,6 +44,7 @@ esp32:
framework:
type: esp-idf
advanced:
flash_chip: generic
minimum_chip_revision: 3.0
sram1_as_iram: true
@@ -33,22 +61,6 @@ packages:
# common: !include common/common.yaml
common_eth: !include common/common_eth.yaml
## UEXT
# 3V3 1 2 GND
# GPIO4 3 4 GPIO36 U1TXD/U1RXD
# GPIO16 5 6 GPIO13 I2C-SCL/I2C-SDA
# GPIO15 7 8 GPIO2 HS2_CMD/HS2_DATA0
# GPIO14 9 10 GPIO5 HS2_CLK/SPI_CS
#
# SD/MMC; shared with UEXT, no CS!!!
# GPIO15 HS2_CMD
# GPIO14 HS2_CLK
# GPIO2 HS2_DATA0
# GPIO34 BUT1
# GPIO35 Battery Measurment ADC
# GPIO39 Ext Power Sense ADC
i2c:
sda: 13
scl: 16
+23 -18
View File
@@ -1,4 +1,22 @@
---
# Hardware: M5Stack ATOM Lite + ATOM Hub Switch
# Pinout:
# GPIO1 UART0 TX
# GPIO3 UART0 RX
# GPIO12 IR
# GPIO19 NC -> Demand [heating_demand] (switch gpio)
# GPIO21 I2C1 SCL -> i2c (i2c scl)
# GPIO22 1-WIRE -> Demand [hot_water_demand] (switch gpio)
# GPIO23 UART1 RX -> uart_modbus (uart rx_pin)
# GPIO25 I2C1 SDA -> i2c (i2c sda)
# GPIO26 I2C0 SDA
# GPIO27 NEO -> atom_led (status LED, common/status_led_atom.yaml)
# GPIO32 I2C0 SCL
# GPIO33 UART1 TX -> uart_modbus (uart tx_pin)
# GPIO39 BUTTON
# I2C:
# 0x18 one_wire_bus (one_wire ds2482)
# 0x27 pca9554_module (pca9554)
substitutions:
device: heater
name: Heater
@@ -25,6 +43,8 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
external_components:
@@ -37,21 +57,8 @@ external_components:
packages:
common: !include common/common.yaml
# PINOUTS: M5ATOM
# IR G12
# NEO G27
# BUTTON G39
# I2C0 SDA G26
# I2C0 SCL G32
# I2C1 SDA G25
# I2C1 SCL G21
# UART0 RX G3
# UART0 TX G1
# UART1 RX G23
# UART1 TX G33
# 1-WIRE G22
# NC G19
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
#logger:
# level: VERBOSE
@@ -129,9 +136,7 @@ globals:
initial_value: '20.5'
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
- id: !extend ha_time
on_time:
- seconds: 0
minutes: /1
+21 -20
View File
@@ -1,4 +1,21 @@
---
# Hardware: M5Stack ATOM Lite + ATOM Hub Switch
# Pinout:
# GPIO1 UART0 TX
# GPIO3 UART0 RX
# GPIO12 IR
# GPIO19 Relay2
# GPIO21 I2C1 SCL -> i2c (i2c scl)
# GPIO22 Relay1 -> power_supply1 (power_supply)
# GPIO23 RS485 Tx
# GPIO25 I2C1 SDA - red -> i2c (i2c sda)
# GPIO26 I2C0 SDA - white
# GPIO27 NEO 1x -> atom_led (status LED, common/status_led_atom.yaml)
# GPIO32 I2C0 SCL
# GPIO33 RS485 Rx
# GPIO39 BUTTON -> Status Button (binary_sensor gpio)
# I2C:
# 0x40 pca9685_hub1 (pca9685)
substitutions:
device: kitchen
name: Kitchen
@@ -32,34 +49,18 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
api:
reboot_timeout: 300s
# PINOUTS: M5ATOM+Atom Hub Switch
# IR G12
# NEO G27 1x
# BUTTON G39
# I2C0 SDA G26 - white
# I2C0 SCL G32
# I2C1 SDA G25 - red
# I2C1 SCL G21
# UART0 RX G3
# UART0 TX G1
# RS485 Rx G33
# RS485 Tx G23
# Relay1 G22
# Relay2 G19
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
i2c:
# - id: i2c0
# sda: 26
+12
View File
@@ -1,4 +1,14 @@
---
# Hardware: M5Stack M5Stamp Pico
# Pinout:
# GPIO22 -> i2c (i2c scl)
# GPIO25 -> i2c (i2c sda)
# GPIO26 -> as3935_i2c (as3935_i2c irq_pin)
# GPIO27 -> neo (light esp32_rmt_led_strip)
# GPIO32 Grove SDA
# GPIO33 Grove SCL
# I2C:
# 0x03 as3935_i2c (as3935_i2c)
substitutions:
device: lightening
name: Lightening detector
@@ -16,6 +26,8 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd # ESP32-PICO-D4, like the other M5Stamp Pico (not read from the device)
type: esp-idf
packages:
+337
View File
@@ -0,0 +1,337 @@
---
# Hardware: Guition ESP32-S3-4848S040
# Pinout:
# # Display (RGB, pins in the mipi_rgb model)
# CS 39
# SCK 48 ST7701S init (3-wire SPI)
# SDA 47
# DE 18
# HSYNC 16
# VSYNC 17
# PCLK 21
# BL 38
# # Capacitive Touch (GT911)
# TP_SDA 19
# TP_SCL 45
# # Relays (86 box variant)
# RELAY1 40
# RELAY2 2
# RELAY3 1
# Used:
# GPIO0 main_display (display mipi_rgb data_pins.red)
# GPIO3 main_display (display mipi_rgb data_pins.green)
# GPIO4 main_display (display mipi_rgb data_pins.blue)
# GPIO5 main_display (display mipi_rgb data_pins.blue)
# GPIO6 main_display (display mipi_rgb data_pins.blue)
# GPIO7 main_display (display mipi_rgb data_pins.blue)
# GPIO8 main_display (display mipi_rgb data_pins.green)
# GPIO9 main_display (display mipi_rgb data_pins.green)
# GPIO10 main_display (display mipi_rgb data_pins.green)
# GPIO11 main_display (display mipi_rgb data_pins.red)
# GPIO12 main_display (display mipi_rgb data_pins.red)
# GPIO13 main_display (display mipi_rgb data_pins.red)
# GPIO14 main_display (display mipi_rgb data_pins.red)
# GPIO15 main_display (display mipi_rgb data_pins.blue)
# GPIO16 main_display (display mipi_rgb hsync_pin)
# GPIO17 main_display (display mipi_rgb vsync_pin)
# GPIO18 main_display (display mipi_rgb de_pin)
# GPIO19 i2c_main (i2c sda)
# GPIO20 main_display (display mipi_rgb data_pins.green)
# GPIO21 main_display (display mipi_rgb pclk_pin)
# GPIO38 gpio_backlight_pwm (output ledc)
# GPIO39 main_display (display mipi_rgb cs_pin)
# GPIO45 i2c_main (i2c scl)
# GPIO46 main_display (display mipi_rgb data_pins.green)
# GPIO47 lcd_spi (spi mosi_pin)
# GPIO48 lcd_spi (spi clk_pin)
# I2C:
# 0x5D main_touch (touchscreen gt911)
substitutions:
device: lvgl-4848s040
name: LVGL 4848S040
area: DEV
comment: "${area} | Guition ESP32-S3-4848S040"
esphome:
name: mcu-${device}
friendly_name: ${name}
area: ${area}
comment: ${comment}
on_boot:
- priority: -100
then:
- lvgl.page.show: status_page
esp32:
variant: esp32s3
flash_size: 16MB
framework:
advanced:
flash_chip: boya
type: esp-idf
# PSRAM bandwidth for the RGB panel (not set by ESPHome); without it the
# image shifts during flash/WiFi activity
sdkconfig_options:
CONFIG_ESP32S3_DATA_CACHE_64KB: y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
CONFIG_SPIRAM_RODATA: y
psram:
mode: octal
speed: 80MHz
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
api:
# status page until Home Assistant connects (log viewers don't subscribe to states)
on_client_connected:
- delay: 2s
- if:
condition:
api.connected:
state_subscription_only: true
then:
- lvgl.page.show: main_page
on_client_disconnected:
- if:
condition:
not:
api.connected:
state_subscription_only: true
then:
- lvgl.page.show: status_page
i2c:
- id: i2c_main
sda: 19
scl: 45
scan: true
spi:
- id: lcd_spi
clk_pin: 48
mosi_pin: 47
display:
- platform: mipi_rgb
model: GUITION-4848S040
id: main_display
spi_id: lcd_spi
update_interval: never
auto_clear_enabled: false
touchscreen:
- platform: gt911
id: main_touch
display: main_display
i2c_id: i2c_main
# the mipi_rgb model mirrors the image on both axes, touch has to follow
transform:
mirror_x: true
mirror_y: true
output:
- platform: ledc
id: gpio_backlight_pwm
pin: 38
frequency: 1220
light:
- platform: monochromatic
id: back_light
name: Backlight
output: gpio_backlight_pwm
restore_mode: ALWAYS_ON
script:
- id: update_status
then:
- lambda: |-
// same colors as the other status screens: ok green, waiting orange, details gray
static const uint32_t OK = 0x4DD966, WAIT = 0xFFB300;
auto set = [](lv_obj_t *label, const std::string &text, uint32_t color) {
lv_label_set_text(label, text.c_str());
lv_obj_set_style_text_color(label, lv_color_hex(color), LV_PART_MAIN);
};
const bool wifi_ok = wifi::global_wifi_component->is_connected();
set(id(status_wifi),
wifi_ok ? str_sprintf("WiFi: connected (%d dBm)", wifi::global_wifi_component->wifi_rssi())
: std::string("WiFi: connecting..."),
wifi_ok ? OK : WAIT);
// IPv6 first (skip link-local), then IPv4
std::string ips;
if (wifi_ok) {
char buf[network::IP_ADDRESS_BUFFER_SIZE];
for (bool v6 : {true, false}) {
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) {
if (!ip.is_set() || ip.is_ip6() != v6)
continue;
ip.str_to(buf);
if (v6 && strncmp(buf, "fe80", 4) == 0)
continue;
if (!ips.empty())
ips += "\n";
ips += buf;
}
}
}
lv_label_set_text(id(status_ips), ips.c_str());
if (ips.empty())
lv_obj_add_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
else
lv_obj_remove_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
const bool api_ok = api::global_api_server->is_connected();
set(id(status_ha), api_ok ? "Home Assistant: connected" : "Home Assistant: waiting...",
api_ok ? OK : WAIT);
const uint32_t up = millis() / 1000;
lv_label_set_text(id(status_footer),
str_sprintf("ESPHome %s · up %ud %02u:%02u:%02u", ESPHOME_VERSION, up / 86400,
(up / 3600) % 24, (up / 60) % 60, up % 60).c_str());
interval:
- interval: 1s
then:
- lvgl.label.update:
id: clock_label
text: !lambda |-
auto now = id(ha_time).now();
if (!now.is_valid())
return std::string("--:--");
return now.strftime("%H:%M");
- if:
condition:
lvgl.page.is_showing: status_page
then:
- script.execute: update_status
image:
- platform: file
file: assets/images/made-for-esphome-white-on-black.svg
id: esphome_logo
resize: 320x95
type: RGB565
transparency: alpha_channel
font:
- file: "gfonts://Roboto@500"
id: font_clock
size: 150
glyphs: "0123456789:-"
- file: "gfonts://Roboto"
id: font_title
size: 32
- file: "gfonts://Roboto"
id: font_status
size: 20
glyphs: "·"
glyphsets: [GF_Latin_Kernel]
lvgl:
log_level: WARN
color_depth: 16
bg_color: 0x000000
text_color: 0xFFFFFF
theme:
buttonmatrix:
bg_opa: TRANSP
border_width: 0
items:
bg_color: 0x2B2F36
text_color: 0xFFFFFF
radius: 12
checked:
bg_color: 0xE08A00
top_layer:
widgets:
# same navigation bar as on mcu-lvgl-trainer
- buttonmatrix:
id: nav_bar
align: bottom_mid
width: 100%
height: 60
pad_all: 4
pad_column: 6
items:
text_font: montserrat_28
rows:
- buttons:
- id: page_prev
text: ""
on_press:
then:
lvgl.page.previous:
- id: page_home
text: ""
on_press:
then:
lvgl.page.show: main_page
- id: page_next
text: ""
on_press:
then:
lvgl.page.next:
pages:
# 1: clock
- id: main_page
widgets:
- label:
id: clock_label
align: CENTER
y: -30
text_font: font_clock
text: "--:--"
# 2: status (shown until Home Assistant connects)
- id: status_page
on_load:
- script.execute: update_status
widgets:
- image:
src: esphome_logo
align: TOP_MID
y: 16
- label:
align: TOP_MID
y: 120
text_font: font_title
text: "${name}"
- obj:
id: status_lines
x: 24
y: 170
width: 440
height: SIZE_CONTENT
bg_opa: TRANSP
border_width: 0
pad_all: 0
scrollbar_mode: "OFF"
layout:
type: flex
flex_flow: column
pad_row: 6
widgets:
- label:
id: status_wifi
text_font: font_status
text: ""
- label:
id: status_ips
text_font: font_status
text_color: 0x8C8C8C
pad_left: 20
text: ""
- label:
id: status_ha
text_font: font_status
text: ""
- label:
id: status_footer
text_font: font_status
text_color: 0x8C8C8C
text: ""
+15
View File
@@ -1,4 +1,17 @@
---
# Hardware: Guition JC3248W535
# Pinout:
# GPIO1 -> main_backlight (power_supply)
# GPIO4 -> touchscreen_bus (i2c sda)
# GPIO8 -> touchscreen_bus (i2c scl)
# GPIO21 -> display_qspi (spi data_pins)
# GPIO39 -> display_qspi (spi data_pins)
# GPIO40 -> display_qspi (spi data_pins)
# GPIO45 -> main_display (display mipi_spi cs_pin)
# GPIO47 -> display_qspi (spi clk_pin)
# GPIO48 -> display_qspi (spi data_pins)
# I2C:
# 0x3B main_touch (touchscreen axs15231)
substitutions:
device: lvgl-eworkbench
name: Electronics Workbench Display
@@ -16,6 +29,8 @@ esp32:
flash_size: 16MB
toolchain: esp-idf
framework:
advanced:
flash_chip: generic # same board as lvgl-trainer (not read from the device)
type: esp-idf
packages:
+628 -150
View File
@@ -1,9 +1,31 @@
---
# Hardware: Guition JC3248W535
# Pinout:
# GPIO1 -> gpio_backlight_pwm (output ledc)
# GPIO4 -> touchscreen_bus (i2c sda)
# GPIO8 -> touchscreen_bus (i2c scl)
# GPIO21 -> display_qspi (spi data_pins)
# GPIO39 -> display_qspi (spi data_pins)
# GPIO40 -> display_qspi (spi data_pins)
# GPIO43 -> ext_uart (uart tx_pin)
# GPIO44 -> ext_uart (uart rx_pin)
# GPIO45 -> main_display (display mipi_spi cs_pin)
# GPIO47 -> display_qspi (spi clk_pin)
# GPIO48 -> display_qspi (spi data_pins)
# I2C:
# 0x3B main_touch (touchscreen axs15231)
substitutions:
device: lvgl-trainer
name: Trainer Display
area: Basement
comment: "${area} | Pain Cave"
light_basement: light.mcu_basement_2_light
light_workbench: light.mcu_basement_2_workbench_light
light_exercise: light.exercise_room
fan: light.mcu_dimmer_exercise_room_fan
# Pages (480x320, navigation bar at the bottom):
# clock, lights, training, fan, stopwatch, status
esphome:
name: mcu-${device}
@@ -15,11 +37,13 @@ esp32:
variant: esp32s3
flash_size: 16MB
framework:
advanced:
flash_chip: generic
type: esp-idf
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
i2c:
- id: touchscreen_bus
@@ -36,71 +60,17 @@ spi:
clk_pin: 47
data_pins: [21, 48, 40, 39]
color:
- id: my_red
red: 100%
green: 0%
blue: 0%
- id: my_orange
red: 100%
green: 50%
blue: 0%
- id: my_yellow
red: 100%
green: 100%
blue: 0%
- id: my_green
red: 0%
green: 100%
blue: 0%
- id: my_blue
red: 0%
green: 0%
blue: 100%
- id: my_teal
red: 0%
green: 100%
blue: 100%
- id: my_gray
red: 70%
green: 70%
blue: 70%
- id: my_white
red: 100%
green: 100%
blue: 100%
font:
- file: "gfonts://Roboto"
id: Roboto_48
size: 48
- file: "gfonts://Roboto"
id: Roboto_36
size: 36
- file: "gfonts://Roboto"
id: Roboto_24
size: 24
- file: "gfonts://Roboto"
id: Roboto_12
size: 12
- file: "gfonts://Roboto"
id: font_std
size: 40
glyphs: "!\"%()+=,-_.:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz/\\[]|&@#'"
- file: "gfonts://Roboto@700"
id: font_title
size: 40
glyphs: "!\"%()+=,-_.:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz/\\[]|&@#'"
globals:
- id: bgcolor
type: Color
initial_value: "Color::random_color()"
# power_supply:
# id: main_backlight
# pin: 1
# enable_on_boot: true
# stopwatch: accumulated time of finished runs + start of the current run
- id: sw_running
type: bool
initial_value: 'false'
- id: sw_start
type: uint32_t
initial_value: '0'
- id: sw_accum
type: uint32_t
initial_value: '0'
output:
- platform: ledc
@@ -119,7 +89,6 @@ display:
- platform: mipi_spi
model: AXS15231
data_rate: 40MHz #20mhz is default
#spi_mode: MODE2
id: main_display
spi_id: display_qspi
dimensions:
@@ -127,11 +96,6 @@ display:
width: 320
cs_pin: 45
auto_clear_enabled: false
# show_test_card: true
# lambda: |-
# it.fill(id(bgcolor));
# it.print(it.get_width()/2, it.get_height()/2-20, id(font_title), TextAlign::CENTER, "ESPHome");
# it.print(it.get_width()/2, it.get_height()/2+20, id(font_std), TextAlign::CENTER, "@UTBDK");
touchscreen:
- platform: axs15231
@@ -142,27 +106,8 @@ touchscreen:
# interrupt_pin:
# number: 3
# ignore_strapping_warning: true
calibration:
x_min: 0
x_max: 479
y_min: 0
y_max: 319
transform:
swap_xy: true
mirror_x: false
mirror_y: true
# on_touch:
# - lambda: |-
# Color newColor;
# do { newColor = Color::random_color(); } while (newColor == id(bgcolor));
# id(bgcolor) = newColor;
# ESP_LOGI("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d",
# touch.x,
# touch.y,
# touch.x_raw,
# touch.y_raw
# );
# no calibration/transform: the driver defaults to the native 320x480 panel and
# LVGL applies its own rotation to touch points
on_release:
- if:
condition: lvgl.is_paused
@@ -183,107 +128,640 @@ uart:
binary_sensor:
- platform: homeassistant
id: exercise_room_light
entity_id: light.exercise_room
id: basement_light
entity_id: ${light_basement}
trigger_on_initial_state: true
on_state:
then:
lvgl.widget.update:
id: exercise_room_light_btn
- lvgl.widget.update:
id: basement_light_btn
state:
checked: !lambda return x;
- platform: homeassistant
id: exercise_room_fan
entity_id: light.mcu_dimmer_exercise_room_fan
id: workbench_light
entity_id: ${light_workbench}
trigger_on_initial_state: true
on_state:
then:
lvgl.widget.update:
id: exercise_room_fan_btn
- lvgl.widget.update:
id: workbench_light_btn
state:
checked: !lambda return x;
- platform: homeassistant
id: exercise_light
entity_id: ${light_exercise}
trigger_on_initial_state: true
on_state:
- lvgl.widget.update:
id: exercise_light_btn
state:
checked: !lambda return x;
# brightness and color temperature only make sense while the light is on
- if:
condition:
lambda: return x;
then:
- lvgl.widget.show: exercise_controls
else:
- lvgl.widget.hide: exercise_controls
- platform: homeassistant
id: fan_on
entity_id: ${fan}
trigger_on_initial_state: true
on_state:
- script.execute: update_fan_buttons
sensor:
- platform: homeassistant
id: fan_brightness
entity_id: ${fan}
attribute: brightness
on_value:
- script.execute: update_fan_buttons
text_sensor:
# light attributes read as text: they are 'None' while the light is off
- platform: homeassistant
id: exercise_brightness
entity_id: ${light_exercise}
attribute: brightness
on_value:
- if:
condition:
lambda: return parse_number<float>(x).has_value();
then:
- lvgl.slider.update:
id: exercise_brightness_slider
value: !lambda return roundf(*parse_number<float>(x) * 100.0f / 255.0f);
- platform: homeassistant
id: exercise_color_temp
entity_id: ${light_exercise}
attribute: color_temp_kelvin
on_value:
- if:
condition:
lambda: return parse_number<float>(x).has_value();
then:
- lvgl.slider.update:
id: exercise_color_temp_slider
value: !lambda return *parse_number<float>(x);
# a running automation (e.g. its delay) has current > 0
- platform: homeassistant
id: training_start_running
entity_id: automation.zwift_enable_fan
attribute: current
on_value:
- script.execute: update_training_status
- platform: homeassistant
id: training_stop_running
entity_id: automation.zwift_disable_fan
attribute: current
on_value:
- script.execute: update_training_status
script:
- id: update_fan_buttons
then:
- lambda: |-
// fan level rounded to the 10 % steps of the buttons, 0 = off
int pct = 0;
if (id(fan_on).state && !std::isnan(id(fan_brightness).state))
pct = (int) roundf(id(fan_brightness).state * 10.0f / 255.0f) * 10;
const int levels[] = {0, 50, 60, 70, 80, 90, 100};
lv_obj_t *matrix = id(fan_matrix)->obj;
for (int i = 0; i < 7; i++) {
if (levels[i] == pct)
lv_buttonmatrix_set_button_ctrl(matrix, i, LV_BUTTONMATRIX_CTRL_CHECKED);
else
lv_buttonmatrix_clear_button_ctrl(matrix, i, LV_BUTTONMATRIX_CTRL_CHECKED);
}
- lvgl.label.update:
id: fan_status_label
text: !lambda |-
if (!id(fan_on).state)
return std::string("Ventilátor vypnutý");
if (std::isnan(id(fan_brightness).state))
return std::string("Ventilátor zapnutý");
return str_sprintf("Ventilátor %.0f %%", id(fan_brightness).state * 100.0f / 255.0f);
- id: update_training_status
then:
- lvgl.label.update:
id: training_status_label
text: !lambda |-
if (id(training_start_running).state != "0" && !id(training_start_running).state.empty())
return std::string("Tréning sa spúšťa, ventilátor sa zapne o 10 min");
if (id(training_stop_running).state != "0" && !id(training_stop_running).state.empty())
return std::string("Tréning sa ukončuje, ventilátor sa vypne o 2 min");
return std::string("");
- id: update_stopwatch
then:
- lvgl.label.update:
id: stopwatch_label
text: !lambda |-
const unsigned ms = id(sw_accum) + (id(sw_running) ? millis() - id(sw_start) : 0);
const unsigned s = ms / 1000;
if (s >= 3600)
return str_sprintf("%u:%02u:%02u", s / 3600, (s / 60) % 60, s % 60);
return str_sprintf("%02u:%02u.%u", s / 60, s % 60, (ms / 100) % 10);
- lvgl.label.update:
id: stopwatch_start_label
text: !lambda |-
return std::string(id(sw_running) ? "Stop" : "Štart");
- id: update_status
then:
- lambda: |-
// same colors as the other status screens: ok green, waiting orange, details gray
static const uint32_t OK = 0x4DD966, WAIT = 0xFFB300;
auto set = [](lv_obj_t *label, const std::string &text, uint32_t color) {
lv_label_set_text(label, text.c_str());
lv_obj_set_style_text_color(label, lv_color_hex(color), LV_PART_MAIN);
};
const bool wifi_ok = wifi::global_wifi_component->is_connected();
set(id(status_wifi),
wifi_ok ? str_sprintf("WiFi: connected (%d dBm)", wifi::global_wifi_component->wifi_rssi())
: std::string("WiFi: connecting..."),
wifi_ok ? OK : WAIT);
// IPv6 first (skip link-local), then IPv4
std::string ips;
if (wifi_ok) {
char buf[network::IP_ADDRESS_BUFFER_SIZE];
for (bool v6 : {true, false}) {
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) {
if (!ip.is_set() || ip.is_ip6() != v6)
continue;
ip.str_to(buf);
if (v6 && strncmp(buf, "fe80", 4) == 0)
continue;
if (!ips.empty())
ips += "\n";
ips += buf;
}
}
}
lv_label_set_text(id(status_ips), ips.c_str());
if (ips.empty())
lv_obj_add_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
else
lv_obj_remove_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
const bool api_ok = api::global_api_server->is_connected();
set(id(status_ha), api_ok ? "Home Assistant: connected" : "Home Assistant: waiting...",
api_ok ? OK : WAIT);
const uint32_t up = millis() / 1000;
lv_label_set_text(id(status_footer),
str_sprintf("ESPHome %s · up %ud %02u:%02u:%02u", ESPHOME_VERSION, up / 86400,
(up / 3600) % 24, (up / 60) % 60, up % 60).c_str());
interval:
- interval: 1s
then:
- lvgl.label.update:
id: clock_label
text: !lambda |-
auto now = id(ha_time).now();
if (!now.is_valid())
return std::string("--:--:--");
return now.strftime("%H:%M:%S");
- interval: 100ms
then:
- if:
condition:
and:
- lambda: return id(sw_running);
- lvgl.page.is_showing: stopwatch_page
then:
- script.execute: update_stopwatch
- interval: 2s
then:
- if:
condition:
lvgl.page.is_showing: status_page
then:
- script.execute: update_status
image:
- platform: file
file: assets/images/made-for-esphome-white-on-black.svg
id: esphome_logo
resize: 280x83
type: RGB565
transparency: alpha_channel
font:
- file: "gfonts://Roboto@500"
id: font_digits
size: 110
glyphs: "0123456789:.-"
- file: "gfonts://Roboto"
id: font_ui
size: 24
glyphs: &sk_glyphs "ÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽáäčďéíĺľňóôŕšťúýž°·"
glyphsets: [GF_Latin_Kernel]
- file: "gfonts://Roboto@500"
id: font_button
size: 34
glyphs: *sk_glyphs
glyphsets: [GF_Latin_Kernel]
- file: "gfonts://Roboto"
id: font_small
size: 18
glyphs: *sk_glyphs
glyphsets: [GF_Latin_Kernel]
lvgl:
rotation: 90
buffer_size: 100%
log_level: WARN
color_depth: 16
default_font: montserrat_18
# on_idle:
# - timeout: !lambda "return (id(display_timeout).state * 1000);"
# then:
# - logger.log: "LVGL is idle"
# - light.turn_off:
# id: display_backlight
# transition_length: 2500ms
# - lvgl.pause:
default_font: font_ui
bg_color: 0x000000
text_color: 0xFFFFFF
theme:
button:
bg_color: 0x2B2F36
radius: 12
checked:
bg_color: 0xE08A00
buttonmatrix:
bg_opa: TRANSP
border_width: 0
items:
bg_color: 0x2B2F36
text_color: 0xFFFFFF
radius: 12
checked:
bg_color: 0xE08A00
slider:
bg_color: 0x2B2F36
indicator:
bg_color: 0xE08A00
knob:
bg_color: 0xFFFFFF
top_layer:
widgets:
- buttonmatrix:
id: nav_bar
align: bottom_mid
# styles: header_footer
pad_all: 0
outline_width: 0
id: top_layer
# items:
# styles: header_footer
width: 100%
height: 56
pad_all: 4
pad_column: 6
items:
text_font: montserrat_28
rows:
- buttons:
- id: page_prev
text: "\uF053"
text: ""
on_press:
then:
lvgl.page.previous:
- id: page_home
text: "\uF015"
text: ""
on_press:
then:
lvgl.page.show: main_page
lvgl.page.show: clock_page
- id: page_next
text: "\uF054"
text: ""
on_press:
then:
lvgl.page.next:
pages:
- id: main_page
# 1: clock (default after boot)
- id: clock_page
widgets:
- label:
text: "ESPHome LVGL Display"
id: clock_label
align: CENTER
text_align: CENTER
text_color: 0xFFFFFF
- id: excercise_page
y: -28
text_font: font_digits
text: "--:--:--"
# 2: basement lights
- id: lights_page
pad_all: 10
widgets:
- label:
align: CENTER
text: 'Hello World!'
- button:
id: exercise_room_light_btn
id: basement_light_btn
align: TOP_LEFT
width: 100
height: 70
width: 148
height: 80
checkable: true
widgets:
- label:
align: CENTER
text: 'Light'
- label:
align: CENTER
text: "Pivnica"
on_click:
- homeassistant.action:
action: light.toggle
data:
entity_id: light.exercise_room
- homeassistant.action:
action: light.toggle
data:
entity_id: ${light_basement}
- button:
id: exercise_room_fan_btn
align: TOP_RIGHT
width: 100
height: 70
id: workbench_light_btn
align: TOP_MID
width: 148
height: 80
checkable: true
widgets:
- label:
align: CENTER
text: 'Fan'
- label:
align: CENTER
text: "Pracovný stôl"
on_click:
- homeassistant.action:
action: light.toggle
data:
entity_id: light.mcu_dimmer_exercise_room_fan
- homeassistant.action:
action: light.toggle
data:
entity_id: ${light_workbench}
- button:
id: exercise_light_btn
align: TOP_RIGHT
width: 148
height: 80
checkable: true
widgets:
- label:
align: CENTER
text: "Posilka"
on_click:
- homeassistant.action:
action: light.toggle
data:
entity_id: ${light_exercise}
- obj:
id: exercise_controls
hidden: true
y: 110
width: 460
height: 120
pad_all: 0
bg_opa: TRANSP
border_width: 0
scrollbar_mode: "OFF"
widgets:
- label:
x: 4
y: 0
text_font: font_small
text: "Posilka jas"
- slider:
id: exercise_brightness_slider
x: 14
y: 32
width: 430
height: 16
min_value: 1
max_value: 100
value: 100
on_release:
- homeassistant.action:
action: light.turn_on
data:
entity_id: ${light_exercise}
brightness_pct: !lambda return (int) x;
- label:
x: 4
y: 62
text_font: font_small
text: "Posilka teplota (2700 – 6500 K)"
- slider:
id: exercise_color_temp_slider
x: 14
y: 94
width: 430
height: 16
min_value: 2700
max_value: 6500
value: 2700
on_release:
- homeassistant.action:
action: light.turn_on
data:
entity_id: ${light_exercise}
color_temp_kelvin: !lambda return (int) x;
# 3: training start / stop
- id: training_page
pad_all: 10
widgets:
- button:
align: TOP_LEFT
y: 10
width: 222
height: 150
bg_color: 0x1E7D32
widgets:
- label:
align: CENTER
text_font: font_button
text: "Štart"
on_click:
- homeassistant.action:
action: automation.trigger
data:
entity_id: automation.zwift_enable_fan
- button:
align: TOP_RIGHT
y: 10
width: 222
height: 150
bg_color: 0xB71C1C
widgets:
- label:
align: CENTER
text_font: font_button
text: "Stop"
on_click:
- homeassistant.action:
action: automation.trigger
data:
entity_id: automation.zwift_disable_fan
- label:
id: training_status_label
align: TOP_MID
y: 185
width: 440
text_align: CENTER
text_font: font_small
text: ""
# 4: fan
- id: fan_page
pad_all: 10
widgets:
- buttonmatrix:
id: fan_matrix
align: TOP_MID
width: 460
height: 180
pad_row: 8
pad_column: 8
one_checked: true
items:
text_font: font_button
rows:
- buttons:
- text: "Vyp"
control:
checkable: true
on_press:
- homeassistant.action:
action: light.turn_off
data:
entity_id: ${fan}
- text: "50"
control:
checkable: true
on_press:
- homeassistant.action:
action: light.turn_on
data:
entity_id: ${fan}
brightness_pct: "50"
- text: "60"
control:
checkable: true
on_press:
- homeassistant.action:
action: light.turn_on
data:
entity_id: ${fan}
brightness_pct: "60"
- text: "70"
control:
checkable: true
on_press:
- homeassistant.action:
action: light.turn_on
data:
entity_id: ${fan}
brightness_pct: "70"
- buttons:
- text: "80"
control:
checkable: true
on_press:
- homeassistant.action:
action: light.turn_on
data:
entity_id: ${fan}
brightness_pct: "80"
- text: "90"
control:
checkable: true
on_press:
- homeassistant.action:
action: light.turn_on
data:
entity_id: ${fan}
brightness_pct: "90"
- text: "100"
control:
checkable: true
on_press:
- homeassistant.action:
action: light.turn_on
data:
entity_id: ${fan}
brightness_pct: "100"
- label:
id: fan_status_label
align: TOP_MID
y: 200
text_font: font_small
text: ""
# 5: stopwatch
- id: stopwatch_page
pad_all: 10
widgets:
- label:
id: stopwatch_label
align: TOP_MID
y: 10
text_font: font_digits
text: "00:00.0"
- button:
align: TOP_LEFT
y: 150
width: 222
height: 90
widgets:
- label:
id: stopwatch_start_label
align: CENTER
text_font: font_button
text: "Štart"
on_click:
- lambda: |-
if (id(sw_running)) {
id(sw_accum) += millis() - id(sw_start);
id(sw_running) = false;
} else {
id(sw_start) = millis();
id(sw_running) = true;
}
- script.execute: update_stopwatch
- button:
align: TOP_RIGHT
y: 150
width: 222
height: 90
widgets:
- label:
align: CENTER
text_font: font_button
text: "Reset"
on_click:
- lambda: |-
id(sw_accum) = 0;
id(sw_start) = millis();
- script.execute: update_stopwatch
# 6: status
- id: status_page
on_load:
- script.execute: update_status
widgets:
- image:
src: esphome_logo
align: TOP_MID
y: 8
- label:
align: TOP_MID
y: 96
text: "${name}"
- obj:
id: status_lines
x: 20
y: 126
width: 440
height: SIZE_CONTENT
bg_opa: TRANSP
border_width: 0
pad_all: 0
scrollbar_mode: "OFF"
layout:
type: flex
flex_flow: column
pad_row: 4
widgets:
- label:
id: status_wifi
text_font: font_small
text: ""
- label:
id: status_ips
text_font: font_small
text_color: 0x8C8C8C
pad_left: 16
text: ""
- label:
id: status_ha
text_font: font_small
text: ""
- label:
id: status_footer
text_font: font_small
text_color: 0x8C8C8C
text: ""
+302 -600
View File
@@ -1,4 +1,88 @@
---
# Hardware: Sunton ESP32-8048S043 (CYD 4.3", 800x480, capacitive touch)
# Pinout:
# # Display
# R0 GND
# R1 GND
# R2 GND
# R3 45
# R4 48
# R5 47
# R6 21
# R7 14
# G0 GND
# G1 GND
# G2 5
# G3 6
# G4 7
# G5 15
# G6 16
# G7 4
# B0 GND
# B1 GND
# B2 GND
# B3 8
# B4 3
# B5 46
# B6 9
# B7 1
# DCLK 42
# HSYNC 39
# VSYNC 41
# DE 40
# BL 2
# # Capacitive Touch
# TP_INT
# TP_RST 38
# TP_SDA 19
# TP_SCL 20
# # SDCARD
# TF_CS 10
# SPI_MOSI 11
# SPI_CLK 12
# SPI_MISO 13
# # SPI Conector (HC1.25-4)
# SPI_CS 19
# SPI_MOSI 11
# SPI_CLK 12
# SPI_MISO 13
# # UART1 (SH1.0-4)
# 1 GND
# 2 3V3-ESP
# 3 17
# 4 18
# # UART1, USB Connector (Resistive) / I2C (Capacitive) (HC1.25-4)
# 1 17
# 2 18
# 3 19 TP_SDA
# 4 20 TP_SCL
# Used:
# GPIO1 main_display (display mipi_rgb data_pins.blue)
# GPIO2 gpio_backlight_pwm (output ledc)
# GPIO3 main_display (display mipi_rgb data_pins.blue)
# GPIO4 main_display (display mipi_rgb data_pins.green)
# GPIO5 main_display (display mipi_rgb data_pins.green)
# GPIO6 main_display (display mipi_rgb data_pins.green)
# GPIO7 main_display (display mipi_rgb data_pins.green)
# GPIO8 main_display (display mipi_rgb data_pins.blue)
# GPIO9 main_display (display mipi_rgb data_pins.blue)
# GPIO14 main_display (display mipi_rgb data_pins.red)
# GPIO15 main_display (display mipi_rgb data_pins.green)
# GPIO16 main_display (display mipi_rgb data_pins.green)
# GPIO19 i2c_main (i2c sda)
# GPIO20 i2c_main (i2c scl)
# GPIO21 main_display (display mipi_rgb data_pins.red)
# GPIO38 main_touch (touchscreen gt911 reset_pin)
# GPIO39 main_display (display mipi_rgb hsync_pin)
# GPIO40 main_display (display mipi_rgb de_pin)
# GPIO41 main_display (display mipi_rgb vsync_pin)
# GPIO42 main_display (display mipi_rgb pclk_pin)
# GPIO45 main_display (display mipi_rgb data_pins.red)
# GPIO46 main_display (display mipi_rgb data_pins.blue)
# GPIO47 main_display (display mipi_rgb data_pins.red)
# GPIO48 main_display (display mipi_rgb data_pins.red)
# I2C:
# 0x5D main_touch (touchscreen gt911)
substitutions:
device: lvgl
name: LVGL
@@ -10,18 +94,22 @@ esphome:
friendly_name: ${name}
area: ${area}
comment: ${comment}
platformio_options:
board_build.flash_mode: dio
on_boot:
- priority: -100
then:
- lvgl.page.show: status_page
esp32:
variant: esp32s3
flash_size: 16MB
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
# Required to achieve sufficient PSRAM bandwidth
# PSRAM bandwidth for the RGB panel (not set by ESPHome); without it the
# image shifts during flash/WiFi activity
sdkconfig_options:
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: y
CONFIG_ESP32S3_DATA_CACHE_64KB: y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
CONFIG_SPIRAM_RODATA: y
@@ -32,62 +120,26 @@ psram:
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# PINOUTS: ESP32 Cheap Yellow Display, 4.3", IPS, Capacitive
## Display
# R0 GND
# R1 GND
# R2 GND
# R3 45
# R4 48
# R5 47
# R6 21
# R7 14
# G0 GND
# G1 GND
# G2 5
# G3 6
# G4 7
# G5 15
# G6 16
# G7 4
# B0 GND
# B1 GND
# B2 GND
# B3 8
# B4 3
# B5 46
# B6 9
# B7 1
# DCLK 42
# HSYNC 39
# VSYNC 41
# DE 40
## Capacitive Touch
# TP_INT
# TP_RST 38
# TP_SDA 19
# TP_SCL 20
## SDCARD
# TF_CS 10
# SPI_MOSI 11
# SPI_CLK 12
# SPI_MISO 13
## SPI Conector (HC1.25-4)
# SPI_CS 19
# SPI_MOSI 11
# SPI_CLK 12
# SPI_MISO 13
## UART1 (SH1.0-4)
# 1 GND
# 2 3V3-ESP
# 3 17
# 4 18
## UART1, USB Connector (Resistive) / I2C (Capacitive) (HC1.25-4)
# 1 17
# 2 18
# 3 19 TP_SDA
# 4 20 TP_SCL
api:
# status page until Home Assistant connects (log viewers don't subscribe to states)
on_client_connected:
- delay: 2s
- if:
condition:
api.connected:
state_subscription_only: true
then:
- lvgl.page.show: main_page
on_client_disconnected:
- if:
condition:
not:
api.connected:
state_subscription_only: true
then:
- lvgl.page.show: status_page
i2c:
- id: i2c_main
@@ -95,573 +147,223 @@ i2c:
scl: 20
scan: true
# same pins and timing as the 5" Sunton board, pclk lowered for the 4.3" panel
display:
- platform: rpi_dpi_rgb
- platform: mipi_rgb
model: ESP32-8048S050
id: main_display
color_order: RGB
invert_colors: true
pclk_frequency: 12.5MHz
update_interval: never
auto_clear_enabled: false # takes 2.8 seconds to clear the display
dimensions:
width: 800
height: 480
de_pin: 40
hsync_pin: 39
vsync_pin: 41
pclk_pin: 42
pclk_frequency: 12.5MHz
hsync_pulse_width: 4
hsync_front_porch: 8
hsync_back_porch: 8
vsync_pulse_width: 4
vsync_front_porch: 8
vsync_back_porch: 8
data_pins:
red:
- 45 # R1
- 48 # R2
- 47 # R3
- 21 # R4
- 14 # R5
green:
- 5 # G0
- 6 # G1
- 7 # G2
- 15 # G3
- 16 # G4
- 4 # G5
blue:
- 8 # B1
- 3 # B2
- 46 # B3
- 9 # B4
- 1 # B5
touchscreen:
- platform: gt911
id: main_touch
display: main_display
i2c_id: i2c_main
reset_pin: 38
# Define a PWM output on the ESP32
output:
- platform: ledc
id: gpio_backlight_pwm
pin: 2
frequency: 1220
id: gpio_backlight_pwm
light:
- platform: monochromatic
output: gpio_backlight_pwm
id: back_light
name: Backlight
output: gpio_backlight_pwm
restore_mode: ALWAYS_ON
text_sensor:
- platform: template
# name: Uptime Human Readable
id: uptime_human
icon: mdi:clock-start
internal: True
time:
- platform: homeassistant
id: time_comp
number:
- platform: template
initial_value: 0
id: counting_number
internal: True
min_value: -10
max_value: 10
step: 1
optimistic: True
# debug:
# update_interval: 5s
sensor:
- platform: uptime
id: uptime_counter
update_interval: 1s
accuracy_decimals: 0
on_raw_value:
then:
- light.turn_on:
id: back_light
brightness: 90%
- number.increment:
id: counting_number
cycle: True
- script.execute: update_display
# - platform: debug
# free:
# name: "${name} Heap Free"
# block:
# name: "${name} Heap Max Block"
# loop_time:
# name: "${name} Loop Time"
# psram:
# name: "${name} Free PSRAM"
- platform: uptime
# name: Uptime Sensor
internal: True
id: uptime_sensor
update_interval: 1s
on_raw_value:
then:
- text_sensor.template.publish:
id: uptime_human
state: !lambda |-
int seconds = round(id(uptime_sensor).raw_state);
int days = seconds / (24 * 3600);
seconds = seconds % (24 * 3600);
int hours = seconds / 3600;
seconds = seconds % 3600;
int minutes = seconds / 60;
seconds = seconds % 60;
return (
("Uptime ") +
(days ? to_string(days) + "d " : "") +
(hours ? to_string(hours) + "h " : "") +
(minutes ? to_string(minutes) + "m " : "") +
(to_string(seconds) + "s")
).c_str();
script:
- id: update_display
- id: update_status
then:
- lambda: |-
// same colors as the other status screens: ok green, waiting orange, details gray
static const uint32_t OK = 0x4DD966, WAIT = 0xFFB300;
auto set = [](lv_obj_t *label, const std::string &text, uint32_t color) {
lv_label_set_text(label, text.c_str());
lv_obj_set_style_text_color(label, lv_color_hex(color), LV_PART_MAIN);
};
const bool wifi_ok = wifi::global_wifi_component->is_connected();
set(id(status_wifi),
wifi_ok ? str_sprintf("WiFi: connected (%d dBm)", wifi::global_wifi_component->wifi_rssi())
: std::string("WiFi: connecting..."),
wifi_ok ? OK : WAIT);
// IPv6 first (skip link-local), then IPv4
std::string ips;
if (wifi_ok) {
char buf[network::IP_ADDRESS_BUFFER_SIZE];
for (bool v6 : {true, false}) {
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) {
if (!ip.is_set() || ip.is_ip6() != v6)
continue;
ip.str_to(buf);
if (v6 && strncmp(buf, "fe80", 4) == 0)
continue;
if (!ips.empty())
ips += "\n";
ips += buf;
}
}
}
lv_label_set_text(id(status_ips), ips.c_str());
if (ips.empty())
lv_obj_add_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
else
lv_obj_remove_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
const bool api_ok = api::global_api_server->is_connected();
set(id(status_ha), api_ok ? "Home Assistant: connected" : "Home Assistant: waiting...",
api_ok ? OK : WAIT);
const uint32_t up = millis() / 1000;
lv_label_set_text(id(status_footer),
str_sprintf("ESPHome %s · up %ud %02u:%02u:%02u", ESPHOME_VERSION, up / 86400,
(up / 3600) % 24, (up / 60) % 60, up % 60).c_str());
interval:
- interval: 1s
then:
# - lvgl.indicator.line.update:
# id: power_meter_input
# value: !lambda return id(counting_number).state;
- lvgl.label.update:
id: battery_kw
id: clock_label
text: !lambda |-
static char buf[8];
snprintf(buf, sizeof(buf), "%.1fkW", id(counting_number).state);
return buf;
- lvgl.label.update:
id: battery_status
text_color: 0xFF0000
#text: "charging"
text: "discharging"
- lvgl.label.update:
id: battery_soc
text: !lambda |-
static char buf[8];
snprintf(buf, sizeof(buf), "%.1f%%", id(counting_number).state);
return buf;
- lvgl.label.update:
id: solar_kw
text: !lambda |-
static char buf[8];
snprintf(buf, sizeof(buf), "%.1fkW", id(counting_number).state);
return buf;
# - lvgl.img.update:
# id: img_solar_power
# src: solar_power_icon
# img_recolor: 0xFFF000 #mixes this color with the base image
# #img_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
# #bg_color: 0xFFFFFF
# # - lvgl.indicator.line.update:
# # id: power_meter_input2
# # value: !lambda return id(counting_number).state;
- lvgl.label.update:
id: battery_kw2
text: !lambda |-
static char buf[8];
snprintf(buf, sizeof(buf), "%.1fkW", id(counting_number).state);
return buf;
- lvgl.label.update:
id: battery_status2
text_color: 0xFF0000
#text: "charging"
text: "discharging"
- lvgl.label.update:
id: battery_soc2
text: !lambda |-
static char buf[8];
snprintf(buf, sizeof(buf), "%.1f%%", id(counting_number).state);
return buf;
- lvgl.label.update:
id: solar_kw2
text: !lambda |-
static char buf[8];
snprintf(buf, sizeof(buf), "%.1fkW", id(counting_number).state);
return buf;
# - lvgl.img.update:
# id: img_solar_power2
# src: solar_power_icon
# img_recolor: 0xFFF000 #mixes this color with the base image
# #img_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
# #bg_color: 0xFFFFFF
auto now = id(ha_time).now();
if (!now.is_valid())
return std::string("--:--");
return now.strftime("%H:%M");
- if:
condition:
lvgl.page.is_showing: status_page
then:
- script.execute: update_status
image:
- file: mdi:sun-wireless-outline
#"solar-power-invert.png"
# mdi:solar-power
# mdi:battery-charging-outline
# mdi:battery-arrow-up-outline
# mdi:battery-arrow-down-outline
id: solar_power_icon
resize: 50x50
type: BINARY
- platform: file
file: assets/images/made-for-esphome-white-on-black.svg
id: esphome_logo
resize: 400x118
type: RGB565
transparency: alpha_channel
- file: mdi:battery-arrow-down-outline
id: home_battery_icon
resize: 30x30
type: BINARY
font:
- file: "gfonts://Roboto@500"
id: font_clock
size: 200
glyphs: "0123456789:-"
- file: "gfonts://Roboto"
id: font_title
size: 40
- file: "gfonts://Roboto"
id: font_status
size: 26
glyphs: "·"
glyphsets: [GF_Latin_Kernel]
lvgl:
log_level: INFO
log_level: WARN
color_depth: 16
#buffer_size: 25%
bg_color: 0
border_width: 0
outline_width: 0
shadow_width: 0
text_font: unscii_16
align: center
style_definitions:
- id: meter_style
text_font: unscii_8
#state_default: null
- id: font_style
text_font: MONTSERRAT_24
#text_font: unscii_16
align: center
text_color: 0xFFFFFF
#bg_opa: cover
bg_color: 0x000000
text_color: 0xFFFFFF
theme:
buttonmatrix:
bg_opa: TRANSP
bg_color: 0
radius: 4
pad_all: 2
- id: details_style
text_font: MONTSERRAT_18
align: center
text_color: 0xFFFFFF
#bg_opa: cover
bg_opa: TRANSP
bg_color: 0
radius: 4
pad_all: 2
widgets:
- obj: # Meter
height: 240
width: 240
#bg_opa: TRANSP
bg_color: 0
border_width: 0
outline_width: 0
shadow_width: 0
pad_all: 4
align: TOP_LEFT
#scrollbar_mode: "off"
widgets:
- meter: # Gradient color arc
height: 100%
width: 100%
border_width: 0
outline_width: 0
align: center
bg_color: 0
styles: meter_style
#bg_opa: TRANSP
scales:
angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right
range_to: 10
range_from: -10
ticks:
count: 0
indicators:
- line:
id: power_meter_input
width: 8
color: 0xFFFFFF
r_mod: 12 #sets line length by this much difference from the scale default radius
value: 50
# - image:
# id: power_meter_input_img
- arc:
color: 0xFF3000
r_mod: 10 #radius difference from the scale default radius
width: 20
start_value: -10
end_value: 0
- arc:
color: 0x00FF00
r_mod: 10 #radius difference from the scale default radius
width: 20
start_value: 0
end_value: 10
#- canvas:
- arc: # black arc to erase middle part of meter indicator line
height: 160
width: 160
align: center
arc_color: 0x000000 # background color
arc_width: 150
start_angle: 0
end_angle: 360
indicator:
arc_width: 150
arc_color: 0x000000
- label: # gauge lower and higher range indicators
styles: font_style
text_font: MONTSERRAT_18 # override font size
y: 8 #negative = higher
x: -99
text: "-10"
- label:
styles: font_style
text_font: MONTSERRAT_18 # override font size
y: 8 #negative = higher
x: 99
text: "+10"
- label:
styles: font_style
id: battery_status
y: -35 #negative = higher
- label:
styles: font_style
id: battery_kw
y: -60
- label:
styles: font_style
text_font: MONTSERRAT_40 # override font size
id: battery_soc
y: 0
- label:
styles: font_style
id: solar_kw
text_color: 0xFFFF00
y: 90
#- img:
# src: home_battery_icon
#id: img_solar_power
#align: center
#img_recolor: 0xFFFFFF
#img_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
#bg_color: 0xFFFFFF
#y: -35
#x: -60
- image:
src: solar_power_icon
id: img_solar_power
align: center
image_recolor: 0xFFFF00
image_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
#bg_color: 0xFFFFFF
y: 50
#x: -60
- obj: # Meter
height: 240
width: 240
#bg_opa: TRANSP
bg_color: 0
border_width: 0
outline_width: 0
shadow_width: 0
pad_all: 4
align: TOP_MID
#scrollbar_mode: "off"
widgets:
- meter: # Gradient color arc
height: 100%
width: 100%
border_width: 0
outline_width: 0
align: center
bg_color: 0
styles: meter_style
#bg_opa: TRANSP
scales:
angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right
range_to: 10
range_from: -10
ticks:
count: 0
indicators:
- line:
id: power_meter_input2
width: 8
color: 0xFFFFFF
r_mod: 12 #sets line length by this much difference from the scale default radius
value: 50
# - image:
# id: power_meter_input_img2
- arc:
color: 0xFF3000
r_mod: 10 #radius difference from the scale default radius
width: 20
start_value: -10
end_value: 0
- arc:
color: 0x00FF00
r_mod: 10 #radius difference from the scale default radius
width: 20
start_value: 0
end_value: 10
#- canvas:
- arc: # black arc to erase middle part of meter indicator line
height: 160
width: 160
align: center
arc_color: 0x000000 # background color
arc_width: 150
start_angle: 0
end_angle: 360
indicator:
arc_width: 150
arc_color: 0x000000
- label: # gauge lower and higher range indicators
styles: font_style
text_font: MONTSERRAT_18 # override font size
y: 8 #negative = higher
x: -99
text: "-10"
- label:
styles: font_style
text_font: MONTSERRAT_18 # override font size
y: 8 #negative = higher
x: 99
text: "+10"
- label:
styles: font_style
id: battery_status2
y: -35 #negative = higher
- label:
styles: font_style
id: battery_kw2
y: -60
- label:
styles: font_style
text_font: MONTSERRAT_40 # override font size
id: battery_soc2
y: 0
- label:
styles: font_style
id: solar_kw2
text_color: 0xFFFF00
y: 90
#- img:
# src: home_battery_icon
#id: img_solar_power
#align: center
#img_recolor: 0xFFFFFF
#img_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
#bg_color: 0xFFFFFF
#y: -35
#x: -60
- image:
src: solar_power_icon
id: img_solar_power2
align: center
image_recolor: 0xFFFF00
image_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
#bg_color: 0xFFFFFF
y: 50
#x: -60
- obj: # Meter
height: 240
width: 240
#bg_opa: TRANSP
bg_color: 0
border_width: 0
outline_width: 0
shadow_width: 0
pad_all: 4
align: BOTTOM_LEFT
#scrollbar_mode: "off"
widgets:
- meter: # Gradient color arc
height: 100%
width: 100%
border_width: 0
outline_width: 0
align: center
bg_color: 0
styles: meter_style
#bg_opa: TRANSP
scales:
angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right
range_to: 10
range_from: -10
ticks:
count: 0
indicators:
- line:
id: power_meter_input3
width: 8
color: 0xFFFFFF
r_mod: 12 #sets line length by this much difference from the scale default radius
value: 50
# - image:
# id: power_meter_input_img3
- arc:
color: 0xFF3000
r_mod: 10 #radius difference from the scale default radius
width: 20
start_value: -10
end_value: 0
- arc:
color: 0x00FF00
r_mod: 10 #radius difference from the scale default radius
width: 20
start_value: 0
end_value: 10
#- canvas:
- arc: # black arc to erase middle part of meter indicator line
height: 160
width: 160
align: center
arc_color: 0x000000 # background color
arc_width: 150
start_angle: 0
end_angle: 360
indicator:
arc_width: 150
arc_color: 0x000000
- label: # gauge lower and higher range indicators
styles: font_style
text_font: MONTSERRAT_18 # override font size
y: 8 #negative = higher
x: -99
text: "-10"
- label:
styles: font_style
text_font: MONTSERRAT_18 # override font size
y: 8 #negative = higher
x: 99
text: "+10"
- label:
styles: font_style
id: battery_status3
y: -35 #negative = higher
- label:
styles: font_style
id: battery_kw3
y: -60
- label:
styles: font_style
text_font: MONTSERRAT_40 # override font size
id: battery_soc3
y: 0
- label:
styles: font_style
id: solar_kw3
text_color: 0xFFFF00
y: 90
#- img:
# src: home_battery_icon
#id: img_solar_power
#align: center
#img_recolor: 0xFFFFFF
#img_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
#bg_color: 0xFFFFFF
#y: -35
#x: -60
- image:
src: solar_power_icon
id: img_solar_power3
align: center
image_recolor: 0xFFFF00
image_recolor_opa: 100% #opacity defaults to 0% = must set this for recolor to take effect
#bg_color: 0xFFFFFF
y: 50
#x: -60
border_width: 0
items:
bg_color: 0x2B2F36
text_color: 0xFFFFFF
radius: 12
checked:
bg_color: 0xE08A00
top_layer:
widgets:
# same navigation bar as on mcu-lvgl-trainer
- buttonmatrix:
id: nav_bar
align: bottom_mid
width: 100%
height: 64
pad_all: 4
pad_column: 6
items:
text_font: montserrat_28
rows:
- buttons:
- id: page_prev
text: "\uF053"
on_press:
then:
lvgl.page.previous:
- id: page_home
text: "\uF015"
on_press:
then:
lvgl.page.show: main_page
- id: page_next
text: "\uF054"
on_press:
then:
lvgl.page.next:
pages:
# 1: clock
- id: main_page
widgets:
- label:
id: clock_label
align: CENTER
y: -32
text_font: font_clock
text: "--:--"
# 2: status (shown until Home Assistant connects)
- id: status_page
on_load:
- script.execute: update_status
widgets:
- image:
src: esphome_logo
align: TOP_MID
y: 16
- label:
align: TOP_MID
y: 140
text_font: font_title
text: "${name}"
- obj:
id: status_lines
x: 60
y: 196
width: 700
height: SIZE_CONTENT
bg_opa: TRANSP
border_width: 0
pad_all: 0
scrollbar_mode: "OFF"
layout:
type: flex
flex_flow: column
pad_row: 8
widgets:
- label:
id: status_wifi
text_font: font_status
text: ""
- label:
id: status_ips
text_font: font_status
text_color: 0x8C8C8C
pad_left: 30
text: ""
- label:
id: status_ha
text_font: font_status
text: ""
- label:
id: status_footer
text_font: font_status
text_color: 0x8C8C8C
text: ""
+600 -77
View File
@@ -1,97 +1,404 @@
---
# Hardware: M5Stack M5Paper
# Pinout:
# GPIO2 -> main_power (switch gpio)
# GPIO5 -> ext_power (switch gpio)
# GPIO12 -> spi (spi mosi_pin)
# GPIO13 -> spi (spi miso_pin)
# GPIO14 -> spi (spi clk_pin)
# GPIO15 -> m5paper_display (display it8951 cs_pin)
# GPIO21 -> i2c_main (i2c sda)
# GPIO22 -> i2c_main (i2c scl)
# GPIO23 -> m5paper_display (display it8951 reset_pin)
# GPIO27 -> m5paper_display (display it8951 busy_pin)
# GPIO35 -> Battery Voltage (sensor adc)
# GPIO36 -> gt911_touchscreen (touchscreen gt911 interrupt_pin)
# GPIO37 -> M5Paper Button UP (binary_sensor gpio) (inverted)
# GPIO38 -> M5Paper Button Press (binary_sensor gpio) (inverted)
# GPIO39 -> M5Paper Button Down (binary_sensor gpio) (inverted)
# I2C:
# 0x44 sensor sht3xd (sensor sht3xd)
# 0x51 rtc_time (time bm8563)
# 0x5D gt911_touchscreen (touchscreen gt911)
substitutions:
device: m5paper
name: M5Paper
area: DEV
comment: M5Paper
waste_calendar: calendar.https_www_hviezdoslavov_sk_kalendar_icalfeed_category_0_ongoing_1
# contacts + manual
birthday_calendars: calendar.birthdays, calendar.narodeniny
# Power modes
# - USB: always on, WiFi + API, events refreshed and redrawn after midnight
# - battery: RTC wakes the board at 00:05, it refreshes the events, draws them and powers
# itself off; the RTC timer lasts at most 255 min, so the wake-ups on the way to
# midnight only re-arm it
# The power button (and USB) also connects to WiFi: the events are refreshed on every
# Home Assistant connection outside the battery cycle.
# Screens: status (after power-on, until Home Assistant connects) and calendar
# The mode is detected by trying to power off: on USB the board keeps running.
esphome:
name: mcu-${device}
friendly_name: ${name}
area: ${area}
comment: ${comment}
includes:
- include/m5paper_calendar.h
on_boot:
- priority: 600
then:
- lambda: |-
// BM8563 CONTROL_STATUS_2: TF (bit 2) is set when the timer woke us up
const uint8_t reg = 0x01;
uint8_t status = 0;
if (id(i2c_main)->write_readv(0x51, &reg, 1, &status, 1) == i2c::ERROR_OK) {
id(rtc_wake) = status & 0x04;
// clear TF and TIE so the RTC releases the power latch
const uint8_t clear[2] = {reg, uint8_t(status & ~0x05)};
id(i2c_main)->write(0x51, clear, 2);
}
m5paper_calendar::load(m5paper_calendar::events());
ESP_LOGI("m5paper", "Wake-up: %s, events: %u", id(rtc_wake) ? "RTC" : "power-on", m5paper_calendar::events().count);
- priority: -100
then:
- if:
condition:
lambda: return id(rtc_wake);
then:
- script.execute: battery_cycle
else:
# power button / USB: stay awake for a while (logs, OTA), then decide the mode
- wifi.enable:
# IT8951 init runs asynchronously after setup
- delay: 3s
- component.update: m5paper_display
- delay: 2min
- script.execute: battery_cycle
esp32:
variant: esp32
toolchain: esp-idf
framework:
type: esp-idf
advanced:
flash_chip: generic
minimum_chip_revision: 3.0
sram1_as_iram: true
psram:
external_components:
- source: github://Passific/m5paper_esphome
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
on_time_sync:
- bm8563.write_time
- platform: bm8563
id: rtc_time
sleep_duration: 3600000ms
globals:
- id: show_status
type: bool
initial_value: 'true'
- id: usb_mode
type: bool
initial_value: 'false'
- id: rtc_wake
type: bool
initial_value: 'false'
# battery cycle running: calendar screen regardless of the connection state
- id: calendar_page
type: bool
initial_value: 'false'
- id: fetch_done
type: bool
initial_value: 'false'
- id: sleep_s
type: int
initial_value: '900'
m5paper:
battery_power_pin: GPIO5
main_power_pin: GPIO2
# update_interval: 10s
# battery_voltage:
# name: "${name} Battery"
wifi:
enable_on_boot: false
on_connect:
- if:
condition:
lambda: return id(show_status) && !id(calendar_page);
then:
- component.update: m5paper_display
api:
# status screen until Home Assistant connects (log viewers don't subscribe to states)
on_client_connected:
- delay: 2s
- if:
condition:
api.connected:
state_subscription_only: true
then:
- lambda: id(show_status) = false;
- if:
condition:
lambda: return !id(calendar_page);
then:
- component.update: m5paper_display
# outside the battery cycle (power button, USB) WiFi is up anyway: always refresh
- if:
condition:
and:
- lambda: return !id(calendar_page);
- api.connected:
state_subscription_only: true
then:
- script.execute: fetch_events
on_client_disconnected:
- if:
condition:
not:
api.connected:
state_subscription_only: true
then:
- lambda: id(show_status) = true;
- if:
condition:
lambda: return !id(calendar_page);
then:
- component.update: m5paper_display
# I2C devices (i2c_main)
# 0x44 SHT30
# 0x50
# 0x51
# 0x5D GT911
# 0x50 FM24C02 EEPROM (unused)
# 0x51 BM8563 RTC
# 0x5D GT911 touch (docs say 0x14; the driver tries 0x5D, then 0x14)
i2c:
- id: i2c_main
sda: 21
scl: 22
scan: true #false
scan: true
# Port A
# - id: i2c_a
# sda: 25
# scl: 32
# scan: true #false
# Port B
# - id: i2c_b
# sda: 26
# scl: 33
# scan: true #false
# Port C
# - id: i2c_c
# sda: 18
# scl: 19
# scan: true #false
spi:
clk_pin: 14
miso_pin: 13
mosi_pin: 12
switch:
# Power control MOS (no PMU on M5Paper); on battery the device powers off when this goes low
- platform: gpio
id: main_power
pin:
number: GPIO2
ignore_strapping_warning: true
restore_mode: ALWAYS_ON
internal: true
# External power (Grove ports)
- platform: gpio
id: ext_power
pin:
number: GPIO5
ignore_strapping_warning: true
restore_mode: ALWAYS_ON
internal: true
script:
# One wake-up on battery: refresh the events if they are old, draw them, power off
- id: battery_cycle
mode: single
then:
- lambda: id(calendar_page) = true;
- wait_until:
condition:
lambda: return id(rtc_time).now().is_valid();
timeout: 10s
- if:
# RTC wake-up on the way to midnight: nothing to draw
condition:
lambda: |-
const auto now = id(rtc_time).now();
return id(rtc_wake) && now.is_valid() && now.hour != 0;
then:
- script.execute: try_sleep
else:
- if:
condition:
lambda: return m5paper_calendar::stale(id(rtc_time).now());
then:
- wifi.enable:
- wait_until:
condition:
api.connected:
state_subscription_only: true
timeout: 45s
- if:
condition:
api.connected:
state_subscription_only: true
then:
- script.execute: fetch_events
- wait_until:
condition:
lambda: return id(fetch_done);
timeout: 15s
- component.update: m5paper_display
# let the e-paper refresh finish before cutting power
- delay: 4s
- script.execute: try_sleep
# today and the next 31 days (the month grid and the list)
- id: fetch_events
mode: single
then:
- lambda: id(fetch_done) = false;
- homeassistant.action:
action: calendar.get_events
data:
entity_id: ${waste_calendar}, ${birthday_calendars}
start_date_time: !lambda return id(rtc_time).now().strftime("%Y-%m-%d 00:00:00");
duration: "744:00:00"
capture_response: true
on_success:
- lambda: |-
auto &ev = m5paper_calendar::events();
if (m5paper_calendar::parse(response, "${waste_calendar}", id(rtc_time).now().timestamp, ev)) {
const bool saved = m5paper_calendar::save(ev);
ESP_LOGI("m5paper", "Events: %u%s", ev.count, saved ? "" : " (flash write failed)");
} else {
ESP_LOGW("m5paper", "Events: unexpected response");
}
id(fetch_done) = true;
# the battery cycle draws on its own
- if:
condition:
lambda: return !id(calendar_page);
then:
- component.update: m5paper_display
on_error:
- lambda: |-
ESP_LOGW("m5paper", "Events: %s", error.c_str());
id(fetch_done) = true;
# Arm the RTC and cut power; if we are still running afterwards, we are on USB
- id: try_sleep
mode: single
then:
- lambda: |-
// next 00:05; the timer lasts at most 255 min, so get there in steps
const int MAX = 255 * 60;
int duration = MAX;
const auto now = id(rtc_time).now();
if (now.is_valid()) {
const int sod = now.hour * 3600 + now.minute * 60 + now.second;
int left = (86400 + 300 - sod) % 86400;
if (left < 600) // just drawn: the 1/60 Hz RTC timer may wake us up to a minute early
left += 86400;
// leave at least 20 min for the last step, so it cannot fall into the case above
duration = left > MAX ? std::min(MAX, left - 1200) : left;
}
if (duration > 255) // longer timers count whole minutes
duration = (duration + 59) / 60 * 60;
id(sleep_s) = std::min(duration, MAX);
ESP_LOGI("m5paper", "Powering off for %d s", id(sleep_s));
- bm8563.start_timer:
duration: !lambda return id(sleep_s);
# a battery wake-up is shorter than boot_is_good_after: confirm the OTA image
# before cutting power, otherwise the bootloader rolls back
- safe_mode.mark_successful:
- delay: 200ms
- switch.turn_off: main_power
- delay: 2s
# still alive -> USB power
- switch.turn_on: main_power
- lambda: |-
ESP_LOGI("m5paper", "Still running, USB power");
id(usb_mode) = true;
id(rtc_wake) = false;
id(calendar_page) = false;
id(show_status) = !api::global_api_server->is_connected_with_state_subscription();
- wifi.enable:
- component.update: m5paper_display
interval:
# USB mode: the battery voltage drops once USB is unplugged -> go to battery mode
- interval: 5min
then:
- if:
condition:
lambda: |-
static float last = NAN;
const float v = id(battery_voltage).state;
const bool dropped = id(usb_mode) && !std::isnan(last) && last - v > 0.03f;
last = v;
return dropped;
then:
- lambda: |-
ESP_LOGI("m5paper", "Battery voltage dropping, checking USB");
id(usb_mode) = false;
- script.execute: battery_cycle
time:
- id: !extend ha_time
on_time_sync:
- bm8563.write_time
- if:
condition:
lambda: return !id(calendar_page);
then:
- component.update: m5paper_display
on_time:
# new day
- seconds: 0
minutes: 0
hours: 0
then:
- if:
condition:
lambda: return !id(show_status) && !id(calendar_page);
then:
- component.update: m5paper_display
# USB mode: keep the stored events fresh for battery mode
- seconds: 0
minutes: 5
hours: 0
then:
- if:
condition:
and:
- lambda: return id(usb_mode);
- api.connected:
state_subscription_only: true
then:
- script.execute: fetch_events
- platform: bm8563
id: rtc_time
binary_sensor:
- platform: gpio
name: ${name} Button UP
id: button_up
pin:
number: 37
number: GPIO37
inverted: true
on_press:
- component.update: m5paper_display
on_release:
- component.update: m5paper_display
- platform: gpio
name: ${name} Button Press
id: button_press
pin:
number: 38
number: GPIO38
inverted: true
- platform: gpio
name: ${name} Button Down
id: button_down
pin:
number: 39
number: GPIO39
inverted: true
- platform: touchscreen
name: ${name} Top Left Touch Button
@@ -103,51 +410,19 @@ binary_sensor:
y_min: 0
y_max: 100
on_press:
# Example of applying the sleep duration and shutting down to the lowest power mode
- bm8563.apply_sleep_duration
- delay: 1s
- m5paper.shutdown_main_power
- script.execute: battery_cycle
font:
- file: "gfonts://Roboto"
id: font_default
size: 20
- file: "gfonts://Roboto"
id: roboto_32
size: 32
- file: "gfonts://Roboto"
id: roboto_24
size: 24
- file: "gfonts://Roboto"
id: roboto_12
size: 12
display:
- platform: it8951e
id: m5paper_display
cs_pin: GPIO15
reset_pin: GPIO23
busy_pin: GPIO27
rotation: 90
reversed: False
update_interval: "never"
lambda: |-
it.printf(25, 25, id(roboto_32), "%.1f°", id(current_temperature).state);
it.strftime(350, 25, id(roboto_32), "%H:%M:%S", id(rtc_time).now());
touchscreen:
- platform: gt911
display: m5paper_display
id: gt911_touchscreen
interrupt_pin: GPIO36
# display:
# - platform: waveshare_epaper
# cs_pin: 15
# model: 2.90in
# full_update_every: 30
# lambda: |-
# it.print(0, 0, id(font1), "Hello World!");
button:
- platform: template
name: Refresh Display
entity_category: config
on_press:
- component.update: m5paper_display
- platform: template
name: Refresh Calendar
entity_category: config
on_press:
- script.execute: fetch_events
sensor:
- platform: sht3xd
@@ -156,9 +431,257 @@ sensor:
id: current_temperature
humidity:
name: Humidity
id: current_humidity
address: 0x44
update_interval: 60s
- platform: adc
id: battery_voltage
name: Battery Voltage
pin: GPIO35
attenuation: 12db
samples: 16
update_interval: 60s
entity_category: diagnostic
filters:
- multiply: 2.0 # 1:2 voltage divider
- platform: copy
source_id: battery_voltage
id: battery_level
name: Battery
unit_of_measurement: "%"
device_class: battery
accuracy_decimals: 0
filters:
- calibrate_linear:
- 3.3 -> 0.0
- 4.15 -> 100.0
- clamp:
min_value: 0
max_value: 100
# touchscreen:
# - platform: gt911
# interrupt_pin: 36
.image_defaults:
icon: &icon {platform: file, type: BINARY, transparency: chroma_key}
image:
- platform: file
file: assets/images/made-for-esphome-white-on-black.svg
id: esphome_logo
resize: 460x136
type: GRAYSCALE
transparency: alpha_channel
# same order as m5paper_calendar::Kind
- {<<: *icon, file: "mdi:cake-variant", id: icon_birthday, resize: 32x32}
- {<<: *icon, file: "mdi:trash-can", id: icon_waste, resize: 32x32}
- {<<: *icon, file: "mdi:cake-variant", id: mark_birthday, resize: 18x18}
- {<<: *icon, file: "mdi:trash-can", id: mark_waste, resize: 18x18}
font:
- file: "gfonts://Roboto"
id: font_title
size: 48
- file: "gfonts://Roboto"
id: font_status
size: 28
glyphs: &sk_glyphs "ÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽáäčďéíĺľňóôŕšťúýž°·"
glyphsets: [GF_Latin_Kernel]
- file: "gfonts://Roboto"
id: font_small
size: 24
glyphs: *sk_glyphs
glyphsets: [GF_Latin_Kernel]
- file: "gfonts://Roboto"
id: font_footer
size: 18
glyphs: "0123456789abcdef:. "
- file: "gfonts://Roboto@500"
id: font_date
size: 34
glyphs: *sk_glyphs
glyphsets: [GF_Latin_Kernel]
color:
- id: ink
red: 0%
green: 0%
blue: 0%
- id: paper
red: 100%
green: 100%
blue: 100%
display:
- platform: it8951
id: m5paper_display
model: m5stack-m5paper
rotation: 270
update_interval: never
# 1bpp: updates use the fast DU waveform, full GC16 refresh every 30 updates
grayscale: false
dithering: false
lambda: |-
// 540x960 portrait
it.fill(id(paper));
const int w = it.get_width();
const int cx = w / 2;
const float batt = id(battery_level).state;
// status screen after power-on, until Home Assistant connects
if (id(show_status) && !id(calendar_page)) {
it.image(cx, 200, id(esphome_logo), ImageAlign::CENTER);
it.print(cx, 320, id(font_title), id(ink), TextAlign::CENTER, "${name}");
const bool wifi_ok = wifi::global_wifi_component->is_connected();
if (wifi_ok) {
it.printf(40, 440, id(font_status), id(ink), "WiFi: connected (%d dBm)", wifi::global_wifi_component->wifi_rssi());
// IPv6 first (skip link-local), then IPv4
int y = 484;
char buf[network::IP_ADDRESS_BUFFER_SIZE];
for (bool v6 : {true, false}) {
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) {
if (!ip.is_set() || ip.is_ip6() != v6 || y > 590)
continue;
ip.str_to(buf);
if (v6 && strncmp(buf, "fe80", 4) == 0)
continue;
it.print(60, y, id(font_small), id(ink), buf);
y += 34;
}
}
} else {
it.print(40, 440, id(font_status), id(ink), "WiFi: connecting...");
}
const bool api_ok = api::global_api_server->is_connected_with_state_subscription();
it.print(40, 620, id(font_status), id(ink),
api_ok ? "Home Assistant: connected" : "Home Assistant: waiting...");
if (!std::isnan(batt))
it.printf(40, 670, id(font_status), id(ink), "Battery: %.0f%% (%.2f V)", batt, id(battery_voltage).state);
it.printf(40, 720, id(font_status), id(ink), "Calendar: %u events stored", m5paper_calendar::events().count);
it.printf(40, 900, id(font_small), id(ink), "ESPHome %s", ESPHOME_VERSION);
return;
}
// calendar screen
using namespace m5paper_calendar;
image::Image *icons[] = {id(icon_birthday), id(icon_waste)};
image::Image *marks[] = {id(mark_birthday), id(mark_waste)};
static const char *const DAYS[] = {"Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota", "Nedeľa"};
static const char *const DAYS_SHORT[] = {"Po", "Ut", "St", "Št", "Pi", "So", "Ne"};
static const char *const MONTHS[] = {"Január", "Február", "Marec", "Apríl", "Máj", "Jún",
"Júl", "August", "September", "Október", "November", "December"};
const auto &ev = m5paper_calendar::events();
const auto now = id(rtc_time).now();
if (!now.is_valid()) {
it.print(cx, 400, id(font_status), id(ink), TextAlign::CENTER, "Čas nie je k dispozícii");
return;
}
const int32_t today = local_day(now);
// header: date, battery
it.printf(24, 16, id(font_date), id(ink), "%s %d. %d.", DAYS[weekday(today)], now.day_of_month, now.month);
if (!std::isnan(batt))
it.printf(w - 24, 22, id(font_small), id(ink), TextAlign::TOP_RIGHT, "%.0f %%", batt);
// month grid; days with events get the icons of their kinds
const int32_t first = days_from_civil(now.year, now.month, 1);
const int32_t next = now.month == 12 ? days_from_civil(now.year + 1, 1, 1) : days_from_civil(now.year, now.month + 1, 1);
const int dim = next - first, lead = weekday(first);
uint8_t kinds[32] = {};
for (int i = 0; i < ev.count; i++) {
if (ev.items[i].day >= first && ev.items[i].day < next)
kinds[ev.items[i].day - first + 1] |= 1 << ev.items[i].kind;
}
const int col_w = 70, row_h = 54, gx = (w - 7 * col_w) / 2, gy = 150;
it.printf(cx, 70, id(font_status), id(ink), TextAlign::TOP_CENTER, "%s %d", MONTHS[now.month - 1], now.year);
for (int c = 0; c < 7; c++)
it.print(gx + c * col_w + col_w / 2, 116, id(font_small), id(ink), TextAlign::TOP_CENTER, DAYS_SHORT[c]);
for (int d = 1; d <= dim; d++) {
const int cell = lead + d - 1;
const int x = gx + (cell % 7) * col_w, y = gy + (cell / 7) * row_h;
const bool is_today = first + d - 1 == today;
if (is_today)
it.filled_rectangle(x + 3, y + 1, col_w - 6, row_h - 2, id(ink));
const Color fg = is_today ? id(paper) : id(ink);
it.printf(x + col_w / 2, y + 4, id(font_small), fg, TextAlign::TOP_CENTER, "%d", d);
const int n = __builtin_popcount(kinds[d]);
int mx = x + (col_w - n * 20) / 2;
for (int k = 0; k < 2; k++) {
if (kinds[d] & (1 << k)) {
it.image(mx, y + 32, marks[k], fg);
mx += 20;
}
}
}
// next 14 days; waste collection today or tomorrow is inverted: put the bin out
const int top = 490, list_h = 50, max_rows = 8;
it.horizontal_line(24, top - 12, w - 48, id(ink));
int rows = 0, more = 0;
for (int i = 0; i < ev.count; i++) {
const Event &e = ev.items[i];
if (e.day < today || e.day >= today + 14)
continue;
if (rows == max_rows) {
more++;
continue;
}
const int y = top + rows++ * list_h;
const bool urgent = e.kind == WASTE && e.day <= today + 1;
if (urgent)
it.filled_rectangle(16, y, w - 32, list_h - 4, id(ink));
const Color fg = urgent ? id(paper) : id(ink);
const int ty = y + (list_h - 4) / 2;
if (e.day == today)
it.print(28, ty, id(font_small), fg, TextAlign::CENTER_LEFT, "Dnes");
else if (e.day == today + 1)
it.print(28, ty, id(font_small), fg, TextAlign::CENTER_LEFT, "Zajtra");
else {
const auto t = ESPTime::from_epoch_local(uint32_t(e.day) * 86400 + 43200);
it.printf(28, ty, id(font_small), fg, TextAlign::CENTER_LEFT, "%s %d. %d.", DAYS_SHORT[weekday(e.day)],
t.day_of_month, t.month);
}
if (e.kind < 2)
it.image(150, ty - 16, icons[e.kind], fg);
it.start_clipping(194, y, w - 28, y + list_h);
if (e.minute == ALL_DAY)
it.print(194, ty, id(font_small), fg, TextAlign::CENTER_LEFT, e.summary);
else
it.printf(194, ty, id(font_small), fg, TextAlign::CENTER_LEFT, "%02d:%02d %s", e.minute / 60, e.minute % 60,
e.summary);
it.end_clipping();
}
if (!ev.valid())
it.print(cx, top + 20, id(font_small), id(ink), TextAlign::TOP_CENTER, "Kalendár nie je k dispozícii");
else if (rows == 0)
it.print(cx, top + 20, id(font_small), id(ink), TextAlign::TOP_CENTER, "Žiadne udalosti v najbližších 14 dňoch");
else if (more > 0)
it.printf(w - 28, top + rows * list_h, id(font_small), id(ink), TextAlign::TOP_RIGHT, "+%d ďalšie", more);
// footer: IPv6 address (only while WiFi is up), last download
it.horizontal_line(24, 910, w - 48, id(ink));
char buf[network::IP_ADDRESS_BUFFER_SIZE];
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) {
if (!ip.is_set() || !ip.is_ip6())
continue;
ip.str_to(buf);
if (strncmp(buf, "fe80", 4) != 0) {
it.print(24, 944, id(font_footer), id(ink), TextAlign::BOTTOM_LEFT, buf);
break;
}
}
if (ev.valid()) {
const auto f = ESPTime::from_epoch_local(ev.fetched_at);
it.printf(w - 24, 944, id(font_footer), id(ink), TextAlign::BOTTOM_RIGHT, "%d. %d. %02d:%02d", f.day_of_month,
f.month, f.hour, f.minute);
}
touchscreen:
- platform: gt911
id: gt911_touchscreen
display: m5paper_display
# GPIO36 is input-only; INT is only driven as output when reset_pin is set
interrupt_pin:
number: GPIO36
mode:
input: true
output: false
+20 -18
View File
@@ -1,4 +1,19 @@
---
# Hardware: M5Stack ATOM Lite
# Pinout:
# GPIO1 UART0 TX
# GPIO3 UART0 RX
# GPIO12 IR
# GPIO19 NC
# GPIO21 I2C1 SCL
# GPIO22 1-WIRE
# GPIO23 UART1 RX
# GPIO25 I2C1 SDA
# GPIO26 I2C0 SDA -> uart_modbus (uart rx_pin)
# GPIO27 NEO -> atom_led (status LED, common/status_led_atom.yaml)
# GPIO32 I2C0 SCL -> uart_modbus (uart tx_pin)
# GPIO33 UART1 TX
# GPIO39 BUTTON
substitutions:
device: mains-power
name: Mains Power
@@ -22,25 +37,14 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
# PINOUTS: M5ATOM
# IR G12
# NEO G27
# BUTTON G39
# I2C0 SDA G26
# I2C0 SCL G32
# I2C1 SDA G25
# I2C1 SCL G21
# UART0 RX G3
# UART0 TX G1
# UART1 RX G23
# UART1 TX G33
# 1-WIRE G22
# NC G19
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
modbus:
uart_id: uart_modbus
@@ -228,9 +232,7 @@ button:
- pzemac.reset_energy: pzemac_l3
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
- id: !extend ha_time
on_time:
- cron: '0 0 0 * * *'
then:
+1
View File
@@ -1,4 +1,5 @@
---
# Hardware: Nordic nRF52840 DK
esphome:
name: mcu-nrf-dk
friendly_name: mcu-nrf-dk
+29 -167
View File
@@ -1,4 +1,18 @@
---
# Hardware: Sonoff NSPanel (EU)
# Pinout:
# GPIO2 IO2
# GPIO4 Screen power -> Screen Power (switch gpio) (inverted)
# GPIO14 Left button -> Left Button (binary_sensor gpio) (inverted)
# GPIO16 Display UART TX -> display_uart (uart tx_pin)
# GPIO17 Display UART RX -> display_uart (uart rx_pin)
# GPIO19 Relay 2
# GPIO21 Buzzer -> buzzer_out (output ledc)
# GPIO22 Relay 1 -> relay_1 (output gpio)
# GPIO23 Relay 3 (no relay, connector)
# GPIO27 Right button -> Right Button (binary_sensor gpio) (inverted)
# GPIO37 ALS (light sensor)
# GPIO38 NTC temperature (ADC) -> ntc_source (sensor adc)
substitutions:
device: nspanel-bedroom
name: Bedroom NSPanel
@@ -11,103 +25,20 @@ esphome:
friendly_name: ${name}
area: ${area}
comment: ${comment}
on_boot:
then:
- switch.turn_off: screen_power
- delay: 1s
- switch.turn_on: screen_power
- delay: 2s
- lambda: 'id(nspanel_id).set_display_dim(5, 80);'
esp32:
variant: esp32
toolchain: esp-idf
framework:
type: esp-idf
advanced:
minimum_chip_revision: 3.0
sram1_as_iram: true
external_components:
- source:
type: git
url: https://github.com/randybb/esphome-nspanel-lovelace-native
ref: devices
refresh: 0s
components: [nspanel_lovelace]
packages:
common: !include common/common.yaml
script:
- id: apply_sleep_dim
then:
- lambda: |-
uint8_t dim;
if (id(bedroom_lights).state) dim = 5; // sleepOverride
else if (id(sun_id).is_above_horizon(-6)) dim = 5; // day
else dim = 0; // night
id(nspanel_id).set_display_inactive_dim(dim);
api:
homeassistant_services: true
homeassistant_states: true
actions:
- action: play_rtttl
variables:
song: string
then:
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify
variables:
heading: string
message: string
song: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(heading, message, 10000);'
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify_fullscreen
variables:
title: string
description: string
button1: string
button2: string
timeout: int
icon: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(title, description, timeout);'
- rtttl.play: "scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b"
uart:
id: display_uart
tx_pin: 16
rx_pin: 17
baud_rate: 115200
ipv6_only: !include common/ipv6_only.yaml
nspanel: !include
file: common/nspanel.yaml
vars:
temperature_entity: sensor.zigbee_bedroom_temperature
sleep_dim: !include
file: common/nspanel_sleep_dim.yaml
vars:
sleep_override_entity: light.bedroom_lights
nspanel_lovelace:
id: nspanel_id
sleep_timeout: 10
experimental_vertical_ui: true
locale:
language: sk
temperature_unit: celcius
screensaver:
time_id: ha_time
time_format: '%H:%M'
date_format: '%A, %d. %b. %Y'
weather:
entity_id: sensor.weather_forecast_daily
icon_color: [255, 255, 255]
entities:
- entity_id: sensor.zigbee_bedroom_temperature
icon:
value: home-thermometer-outline
color: [255, 255, 255]
precision: 1
cards:
- type: cardGrid
title: Spálňa
@@ -135,12 +66,12 @@ nspanel_lovelace:
title: Kúrenie
thermo_entity_id: climate.bt_trv_bedroom
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
on_time_sync:
- script.execute: apply_sleep_dim
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.bedroom_nspanel_info
icon: information-outline
binary_sensor:
- platform: gpio
@@ -166,12 +97,6 @@ binary_sensor:
entity_id: light.bedroom_lamps
- lambda: 'id(nspanel_id).render_default_page();'
- platform: homeassistant # sleepOverride
id: bedroom_lights
entity_id: light.bedroom_lights
on_state:
- script.execute: apply_sleep_dim
light:
- platform: binary
name: Light
@@ -179,10 +104,6 @@ light:
output: relay_1
output:
- platform: ledc
id: buzzer_out
pin:
number: 21
- id: relay_1
platform: gpio
pin:
@@ -191,62 +112,3 @@ output:
# platform: gpio
# pin:
# number: 19
sun:
id: sun_id
time_id: ha_time
latitude: 48.15°
longitude: 17.11°
on_sunrise:
- elevation: -6°
then:
- script.execute: apply_sleep_dim
on_sunset:
- elevation: -6°
then:
- script.execute: apply_sleep_dim
switch:
- platform: gpio
name: Screen Power
id: screen_power
entity_category: config
pin:
number: 4
inverted: true
restore_mode: ALWAYS_ON
rtttl:
id: buzzer
output: buzzer_out
sensor:
- platform: adc
id: ntc_source
pin: 38
update_interval: 5min
attenuation: 12db
- platform: resistance
id: resistance_sensor
sensor: ntc_source
configuration: DOWNSTREAM
resistor: 11.2kOhm
- platform: ntc
name: Temperature
id: temperature
sensor: resistance_sensor
calibration:
b_constant: 3950
reference_temperature: 25°C
reference_resistance: 10kOhm
text_sensor:
- platform: homeassistant
id: name_day
entity_id: sensor.nameday_sk
on_value:
- lambda: |-
id(nspanel_id).set_time_format("%H:%M~" + x);
id(nspanel_id).update_time();
+24 -5
View File
@@ -1,4 +1,18 @@
---
# Hardware: Sonoff NSPanel (EU)
# Pinout:
# GPIO2 IO2
# GPIO4 Screen power -> Screen Power (switch gpio) (inverted)
# GPIO14 Left button -> Left Button (binary_sensor gpio) (inverted)
# GPIO16 Display UART TX -> display_uart (uart tx_pin)
# GPIO17 Display UART RX -> display_uart (uart rx_pin)
# GPIO19 Relay 2 -> Relay 2 (switch gpio)
# GPIO21 Buzzer -> buzzer_out (output ledc)
# GPIO22 Relay 1 -> Relay 1 (switch gpio)
# GPIO23 Relay 3 (no relay, connector)
# GPIO27 Right button -> Right Button (binary_sensor gpio) (inverted)
# GPIO37 ALS (light sensor)
# GPIO38 NTC temperature (ADC) -> ntc_source (sensor adc)
substitutions:
device: nspanel-dev
name: NSPanel DEV
@@ -37,6 +51,7 @@ esp32:
framework:
type: esp-idf
advanced:
flash_chip: generic
minimum_chip_revision: 3.0
sram1_as_iram: true
@@ -59,6 +74,8 @@ external_components:
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
nspanel_popup: !include common/nspanel_popup.yaml
# common: !include common/common_dev.yaml
# web_server:
@@ -440,6 +457,13 @@ nspanel_lovelace:
- name: Rast trávy
entity_id: automation.irrigation_grow_grass
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.nspanel_dev_info
icon: information-outline
binary_sensor:
- platform: gpio
name: Left Button
@@ -540,11 +564,6 @@ sensor:
- platform: template
id: room_temperature_id
time:
platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
text_sensor:
- platform: homeassistant
id: name_day
+26 -135
View File
@@ -1,4 +1,18 @@
---
# Hardware: Sonoff NSPanel (EU)
# Pinout:
# GPIO2 IO2
# GPIO4 Screen power -> Screen Power (switch gpio) (inverted)
# GPIO14 Left button -> Left Button (binary_sensor gpio) (inverted)
# GPIO16 Display UART TX -> display_uart (uart tx_pin)
# GPIO17 Display UART RX -> display_uart (uart rx_pin)
# GPIO19 Relay 2 -> Dining Table Light MAIN (switch gpio)
# GPIO21 Buzzer -> buzzer_out (output ledc)
# GPIO22 Relay 1 -> Kitchen Worktop Light (switch gpio)
# GPIO23 Relay 3 (no relay, connector)
# GPIO27 Right button -> Right Button (binary_sensor gpio) (inverted)
# GPIO37 ALS (light sensor)
# GPIO38 NTC temperature (ADC) -> ntc_source (sensor adc)
substitutions:
device: nspanel-fireplace
name: Fireplace NSPanel
@@ -10,93 +24,17 @@ esphome:
friendly_name: ${name}
area: ${area}
comment: ${comment}
on_boot:
then:
- switch.turn_off: screen_power
- delay: 1s
- switch.turn_on: screen_power
- delay: 2s
- lambda: 'id(nspanel_id).set_display_dim(5, 80);'
esp32:
variant: esp32
toolchain: esp-idf
framework:
type: esp-idf
advanced:
minimum_chip_revision: 3.0
sram1_as_iram: true
external_components:
- source:
type: git
url: https://github.com/randybb/esphome-nspanel-lovelace-native
ref: devices
refresh: 0s
components: [nspanel_lovelace]
packages:
common: !include common/common.yaml
api:
homeassistant_services: true
homeassistant_states: true
actions:
- action: play_rtttl
variables:
song: string
then:
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify
variables:
heading: string
message: string
song: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(heading, message, 10000);'
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify_fullscreen
variables:
title: string
description: string
button1: string
button2: string
timeout: int
icon: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(title, description, timeout);'
- rtttl.play: "scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b"
uart:
id: display_uart
tx_pin: 16
rx_pin: 17
baud_rate: 115200
ipv6_only: !include common/ipv6_only.yaml
nspanel: !include
file: common/nspanel.yaml
vars:
temperature_entity: sensor.zigbee_living_room_kitchen_temperature
temperature_name: Living Room Temperature
nspanel_lovelace:
id: nspanel_id
sleep_timeout: 10
experimental_vertical_ui: true
locale:
language: sk
temperature_unit: celcius
screensaver:
time_id: ha_time
time_format: '%H:%M'
date_format: '%A, %d. %b. %Y'
weather:
entity_id: sensor.weather_forecast_daily
icon_color: [255, 255, 255]
entities:
- entity_id: sensor.zigbee_living_room_kitchen_temperature
icon:
value: home-thermometer-outline
color: [255, 255, 255]
precision: 1
cards:
- type: cardGrid
title: Kuchyňa / Obývačka
@@ -185,10 +123,12 @@ nspanel_lovelace:
- name: Auto-zatváranie
entity_id: switch.gate_auto_close
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.fireplace_nspanel_info
icon: information-outline
binary_sensor:
- platform: gpio
@@ -240,11 +180,6 @@ binary_sensor:
entity_id: light.mcu_kitchen_stove
- lambda: 'id(nspanel_id).render_default_page();'
- lambda: 'id(nspanel_id).render_next_page();'
output:
- platform: ledc
id: buzzer_out
pin:
number: 21
switch:
- platform: gpio
@@ -259,47 +194,3 @@ switch:
entity_category: config
pin:
number: 19
- platform: gpio
name: Screen Power
id: screen_power
entity_category: config
pin:
number: 4
inverted: true
restore_mode: ALWAYS_ON
rtttl:
id: buzzer
output: buzzer_out
sensor:
- platform: adc
id: ntc_source
pin: 38
update_interval: 5min
attenuation: 12db
- platform: resistance
id: resistance_sensor
sensor: ntc_source
configuration: DOWNSTREAM
resistor: 11.2kOhm
- platform: ntc
name: "Living Room Temperature"
id: temperature
sensor: resistance_sensor
calibration:
b_constant: 3950
reference_temperature: 25°C
reference_resistance: 10kOhm
text_sensor:
- platform: homeassistant
id: name_day
entity_id: sensor.nameday_sk
on_value:
- lambda: |-
id(nspanel_id).set_time_format("%H:%M~" + x);
id(nspanel_id).update_time();
+30 -136
View File
@@ -1,4 +1,18 @@
---
# Hardware: Sonoff NSPanel (EU)
# Pinout:
# GPIO2 IO2
# GPIO4 Screen power -> Screen Power (switch gpio) (inverted)
# GPIO14 Left button -> Left Button (binary_sensor gpio) (inverted)
# GPIO16 Display UART TX -> display_uart (uart tx_pin)
# GPIO17 Display UART RX -> display_uart (uart rx_pin)
# GPIO19 Relay 2
# GPIO21 Buzzer -> buzzer_out (output ledc)
# GPIO22 Relay 1 -> relay_1 (output gpio)
# GPIO23 Relay 3 (no relay, connector)
# GPIO27 Right button -> Right Button (binary_sensor gpio) (inverted)
# GPIO37 ALS (light sensor)
# GPIO38 NTC temperature (ADC) -> ntc_source (sensor adc)
substitutions:
device: nspanel-office-j
name: Office J NSPanel
@@ -10,93 +24,21 @@ esphome:
friendly_name: ${name}
area: ${area}
comment: ${comment}
on_boot:
then:
- switch.turn_off: screen_power
- delay: 1s
- switch.turn_on: screen_power
- delay: 2s
- lambda: 'id(nspanel_id).set_display_dim(5, 80);'
esp32:
variant: esp32
toolchain: esp-idf
framework:
type: esp-idf
advanced:
minimum_chip_revision: 3.0
sram1_as_iram: true
external_components:
- source:
type: git
url: https://github.com/randybb/esphome-nspanel-lovelace-native
ref: devices
refresh: 0s
components: [nspanel_lovelace]
packages:
common: !include common/common.yaml
api:
homeassistant_services: true
homeassistant_states: true
actions:
- action: play_rtttl
variables:
song: string
then:
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify
variables:
heading: string
message: string
song: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(heading, message, 10000);'
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify_fullscreen
variables:
title: string
description: string
button1: string
button2: string
timeout: int
icon: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(title, description, timeout);'
- rtttl.play: "scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b"
uart:
id: display_uart
tx_pin: 16
rx_pin: 17
baud_rate: 115200
ipv6_only: !include common/ipv6_only.yaml
nspanel: !include
file: common/nspanel.yaml
vars:
temperature_entity: sensor.zigbee_office_j_temperature
ntc_reference_temperature: 22°C
sleep_dim: !include
file: common/nspanel_sleep_dim.yaml
vars:
sleep_override_entity: light.office_j_lights
nspanel_lovelace:
id: nspanel_id
sleep_timeout: 10
experimental_vertical_ui: true
locale:
language: sk
temperature_unit: celcius
screensaver:
time_id: ha_time
time_format: '%H:%M'
date_format: '%A, %d. %b. %Y'
weather:
entity_id: sensor.weather_forecast_daily
icon_color: [255, 255, 255]
entities:
- entity_id: sensor.zigbee_office_j_temperature
icon:
value: home-thermometer-outline
color: [255, 255, 255]
precision: 1
cards:
- type: cardGrid
title: Janko
@@ -134,10 +76,12 @@ nspanel_lovelace:
- name: Auto-zatváranie
entity_id: switch.gate_auto_close
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.office_j_nspanel_info
icon: information-outline
binary_sensor:
- platform: gpio
@@ -162,11 +106,6 @@ binary_sensor:
- lambda: 'id(nspanel_id).render_default_page();'
output:
- platform: ledc
id: buzzer_out
pin:
number: 21
- id: relay_1
platform: gpio
pin:
@@ -185,48 +124,3 @@ light:
# # - platform: binary
# # name: Relay 2
# # output: relay_2
switch:
- platform: gpio
name: Screen Power
id: screen_power
entity_category: config
pin:
number: 4
inverted: true
restore_mode: ALWAYS_ON
rtttl:
id: buzzer
output: buzzer_out
sensor:
- platform: adc
id: ntc_source
pin: 38
update_interval: 5min
attenuation: 12db
- platform: resistance
id: resistance_sensor
sensor: ntc_source
configuration: DOWNSTREAM
resistor: 11.2kOhm
- platform: ntc
name: Temperature
id: temperature
sensor: resistance_sensor
calibration:
b_constant: 3950
reference_temperature: 22°C
reference_resistance: 10kOhm
text_sensor:
- platform: homeassistant
id: name_day
entity_id: sensor.nameday_sk
on_value:
- lambda: |-
id(nspanel_id).set_time_format("%H:%M~" + x);
id(nspanel_id).update_time();
+27 -134
View File
@@ -1,4 +1,18 @@
---
# Hardware: Sonoff NSPanel (EU)
# Pinout:
# GPIO2 IO2
# GPIO4 Screen power -> Screen Power (switch gpio) (inverted)
# GPIO14 Left button -> Left Button (binary_sensor gpio) (inverted)
# GPIO16 Display UART TX -> display_uart (uart tx_pin)
# GPIO17 Display UART RX -> display_uart (uart rx_pin)
# GPIO19 Relay 2 -> relay_2 (switch gpio)
# GPIO21 Buzzer -> buzzer_out (output ledc)
# GPIO22 Relay 1 -> relay_1 (output gpio)
# GPIO23 Relay 3 (no relay, connector) -> Presence Light (light esp32_rmt_led_strip)
# GPIO27 Right button -> Right Button (binary_sensor gpio) (inverted)
# GPIO37 ALS (light sensor)
# GPIO38 NTC temperature (ADC) -> ntc_source (sensor adc)
substitutions:
device: nspanel-office-r
name: Office R NSPanel
@@ -10,33 +24,15 @@ esphome:
friendly_name: ${name}
area: ${area}
comment: ${comment}
on_boot:
then:
- switch.turn_off: screen_power
- delay: 1s
- switch.turn_on: screen_power
- delay: 2s
- lambda: 'id(nspanel_id).set_display_dim(5, 80);'
esp32:
variant: esp32
toolchain: esp-idf
framework:
type: esp-idf
advanced:
minimum_chip_revision: 3.0
sram1_as_iram: true
external_components:
- source:
type: git
url: https://github.com/randybb/esphome-nspanel-lovelace-native
ref: devices
refresh: 0s
components: [nspanel_lovelace]
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
nspanel: !include
file: common/nspanel.yaml
vars:
temperature_entity: sensor.zigbee_office_r_temperature
ntc_reference_temperature: 22°C
script:
- id: geiger_click
@@ -55,65 +51,7 @@ script:
return esphome::random_uint32() % 450 + 50;
- script.execute: geiger_click
api:
homeassistant_services: true
homeassistant_states: true
actions:
- action: play_rtttl
variables:
song: string
then:
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify
variables:
heading: string
message: string
song: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(heading, message, 10000);'
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify_fullscreen
variables:
title: string
description: string
button1: string
button2: string
timeout: int
icon: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(title, description, timeout);'
- rtttl.play: "scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b"
uart:
id: display_uart
tx_pin: 16
rx_pin: 17
baud_rate: 115200
nspanel_lovelace:
id: nspanel_id
sleep_timeout: 10
experimental_vertical_ui: true
locale:
language: sk
temperature_unit: celcius
screensaver:
time_id: ha_time
time_format: '%H:%M'
date_format: '%A, %d. %b. %Y'
weather:
entity_id: sensor.weather_forecast_daily
icon_color: [255, 255, 255]
entities:
- entity_id: sensor.zigbee_office_r_temperature
icon:
value: home-thermometer-outline
color: [255, 255, 255]
precision: 1
cards:
- type: cardGrid
title: Romanko
@@ -158,10 +96,12 @@ nspanel_lovelace:
- name: Auto-zatváranie
entity_id: switch.gate_auto_close
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.office_r_nspanel_info
icon: information-outline
binary_sensor:
- platform: gpio
@@ -175,7 +115,7 @@ binary_sensor:
data:
entity_id: light.office_r_desk_strip
- lambda: 'id(nspanel_id).render_default_page();'
- platform: gpio
name: Right Button
pin:
@@ -186,10 +126,6 @@ binary_sensor:
- lambda: 'id(nspanel_id).render_default_page();'
output:
- platform: ledc
id: buzzer_out
pin:
number: 21
- id: relay_1
platform: gpio
pin:
@@ -229,14 +165,6 @@ switch:
id: relay_2
pin:
number: 19
- platform: gpio
name: Screen Power
id: screen_power
entity_category: config
pin:
number: 4
inverted: true
restore_mode: ALWAYS_ON
- platform: template
name: "Geiger Counter"
optimistic: True
@@ -244,38 +172,3 @@ switch:
- script.execute: geiger_click
turn_off_action:
- script.stop: geiger_click
rtttl:
id: buzzer
output: buzzer_out
sensor:
- platform: adc
id: ntc_source
pin: 38
update_interval: 5min
attenuation: 12db
- platform: resistance
id: resistance_sensor
sensor: ntc_source
configuration: DOWNSTREAM
resistor: 11.2kOhm
- platform: ntc
name: Temperature
id: temperature
sensor: resistance_sensor
calibration:
b_constant: 3950
reference_temperature: 22°C
reference_resistance: 10kOhm
text_sensor:
- platform: homeassistant
id: name_day
entity_id: sensor.nameday_sk
on_value:
- lambda: |-
id(nspanel_id).set_time_format("%H:%M~" + x);
id(nspanel_id).update_time();
+45 -140
View File
@@ -1,4 +1,18 @@
---
# Hardware: Sonoff NSPanel (EU)
# Pinout:
# GPIO2 IO2
# GPIO4 Screen power -> Screen Power (switch gpio) (inverted)
# GPIO14 Left button -> Left Button (binary_sensor gpio) (inverted)
# GPIO16 Display UART TX -> display_uart (uart tx_pin)
# GPIO17 Display UART RX -> display_uart (uart rx_pin)
# GPIO19 Relay 2 -> Light MAIN (switch gpio)
# GPIO21 Buzzer -> buzzer_out (output ledc)
# GPIO22 Relay 1 -> Outside Light Back (switch gpio)
# GPIO23 Relay 3 (no relay, connector)
# GPIO27 Right button -> Right Button (binary_sensor gpio) (inverted)
# GPIO37 ALS (light sensor)
# GPIO38 NTC temperature (ADC) -> ntc_source (sensor adc)
substitutions:
device: nspanel-patio
name: Patio NSPanel
@@ -10,96 +24,21 @@ esphome:
friendly_name: ${name}
area: ${area}
comment: ${comment}
on_boot:
then:
- switch.turn_off: screen_power
- delay: 1s
- switch.turn_on: screen_power
- delay: 2s
- lambda: 'id(nspanel_id).set_display_dim(5, 80);'
esp32:
variant: esp32
toolchain: esp-idf
framework:
type: esp-idf
advanced:
minimum_chip_revision: 3.0
sram1_as_iram: true
external_components:
- source:
type: git
url: https://github.com/randybb/esphome-nspanel-lovelace-native
ref: devices
refresh: 0s
components: [nspanel_lovelace]
packages:
common: !include common/common.yaml
api:
homeassistant_services: true
homeassistant_states: true
actions:
- action: play_rtttl
variables:
song: string
then:
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify
variables:
heading: string
message: string
song: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(heading, message, 10000);'
- rtttl.play:
rtttl: !lambda 'return song;'
- action: notify_fullscreen
variables:
title: string
description: string
button1: string
button2: string
timeout: int
icon: string
then:
- lambda: 'id(nspanel_id).notify_on_screensaver(title, description, timeout);'
- rtttl.play: "scale_up:d=32,o=5,b=100:c,c#,d#,e,f#,g#,a#,b"
uart:
id: display_uart
tx_pin: 16
rx_pin: 17
baud_rate: 115200
ipv6_only: !include common/ipv6_only.yaml
nspanel: !include
file: common/nspanel.yaml
vars:
temperature_entity: sensor.zigbee_living_room_kitchen_temperature
temperature_name: Living Room Temperature
nspanel_lovelace:
id: nspanel_id
sleep_timeout: 10
experimental_vertical_ui: true
locale:
language: sk
temperature_unit: celcius
screensaver:
time_id: ha_time
time_format: '%H:%M'
date_format: '%A, %d. %b. %Y'
weather:
entity_id: sensor.weather_forecast_daily
icon_color: [255, 255, 255]
entities:
- entity_id: sensor.zigbee_living_room_kitchen_temperature
icon:
value: home-thermometer-outline
color: [255, 255, 255]
precision: 1
cards:
- type: cardGrid
title: Kuchyňa / Obývačka
id: card_home
entities:
- name: Kuchyňa / Obývačka
entity_id: light.kitchen
@@ -132,6 +71,7 @@ nspanel_lovelace:
- type: cardGrid
title: Von
id: card_outside
entities:
- name: Terasa
entity_id: light.patio_lights
@@ -214,10 +154,12 @@ nspanel_lovelace:
- name: Rast trávy
entity_id: automation.irrigation_grow_grass
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.patio_nspanel_info
icon: information-outline
binary_sensor:
- platform: gpio
@@ -227,9 +169,7 @@ binary_sensor:
inverted: true
on_click:
- switch.toggle: relay_1
- lambda: 'id(nspanel_id).render_default_page();'
- lambda: 'id(nspanel_id).render_next_page();'
- lambda: 'id(nspanel_id).render_next_page();'
- script.execute: show_outside_card
- platform: gpio
name: Right Button
@@ -238,24 +178,23 @@ binary_sensor:
inverted: true
on_click:
if:
# mcu-patio online -> toggle its lights; otherwise (no API or relay_2 cut its power) the relay
condition:
api.connected:
and:
- api.connected:
- binary_sensor.is_on: patio_status
then:
- homeassistant.action:
action: light.toggle
data:
entity_id: light.patio_lights
- lambda: 'id(nspanel_id).render_default_page();'
- lambda: 'id(nspanel_id).render_next_page();'
- lambda: 'id(nspanel_id).render_next_page();'
- script.execute: show_outside_card
else:
- switch.toggle: relay_2
output:
- platform: ledc
id: buzzer_out
pin:
number: 21
- platform: homeassistant
id: patio_status
entity_id: binary_sensor.mcu_patio_status
switch:
- platform: gpio
@@ -272,46 +211,12 @@ switch:
pin:
number: 19
- platform: gpio
name: Screen Power
id: screen_power
entity_category: config
pin:
number: 4
inverted: true
restore_mode: ALWAYS_ON
rtttl:
id: buzzer
output: buzzer_out
sensor:
- platform: adc
id: ntc_source
pin: 38
update_interval: 5min
attenuation: 12db
- platform: resistance
id: resistance_sensor
sensor: ntc_source
configuration: DOWNSTREAM
resistor: 11.2kOhm
- platform: ntc
name: Living Room Temperature
id: temperature
sensor: resistance_sensor
calibration:
b_constant: 3950
reference_temperature: 25°C
reference_resistance: 10kOhm
text_sensor:
- platform: homeassistant
id: name_day
entity_id: sensor.nameday_sk
on_value:
script:
# jump straight to the "Von" card (one render instead of home + next + next):
# make it the default page for a moment, render it, restore the home card
- id: show_outside_card
then:
- lambda: |-
id(nspanel_id).set_time_format("%H:%M~" + x);
id(nspanel_id).update_time();
id(nspanel_id).set_default_page("card_outside");
id(nspanel_id).render_default_page();
id(nspanel_id).set_default_page("card_home");
+14 -7
View File
@@ -1,4 +1,15 @@
---
# Hardware: M5Stack M5Stamp C3
# Pinout:
# GPIO0 I2C SDA
# GPIO1 I2C SCL
# GPIO2 NEO
# GPIO3 BUTTON
# GPIO4 -> led_red (output ledc)
# GPIO5 -> led_green (output ledc)
# GPIO6 -> led_blue (output ledc)
# GPIO20 UART RX
# GPIO21 UART TX
substitutions:
device: office-r
name: Office R
@@ -18,17 +29,13 @@ esp32:
variant: esp32c3
toolchain: esp-idf
framework:
advanced:
flash_chip: generic
type: esp-idf
packages:
common: !include common/common.yaml
# GPIO21 UART TX
# GPIO20 UART RX
# GPIO0 I2C SDA
# GPIO1 I2C SCL
# GPIO2 NEO
# GPIO3 BUTTON
ipv6_only: !include common/ipv6_only.yaml
light:
- platform: rgb
+21 -20
View File
@@ -1,4 +1,21 @@
---
# Hardware: M5Stack ATOM Lite + ATOM Hub Switch
# Pinout:
# GPIO1 UART0 TX
# GPIO3 UART0 RX
# GPIO12 IR
# GPIO19 Relay2 -> Relay (switch gpio)
# GPIO21 I2C1 SCL -> i2c (i2c scl)
# GPIO22 Relay1 -> power_supply1 (power_supply)
# GPIO23 RS485 Tx
# GPIO25 I2C1 SDA - red -> i2c (i2c sda)
# GPIO26 I2C0 SDA - white
# GPIO27 NEO 1x -> atom_led (status LED, common/status_led_atom.yaml)
# GPIO32 I2C0 SCL
# GPIO33 RS485 Rx
# GPIO39 BUTTON -> Status Button (binary_sensor gpio)
# I2C:
# 0x40 pca9685_hub1 (pca9685)
substitutions:
device: patio
name: Patio
@@ -33,32 +50,16 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
# PINOUTS: M5ATOM+Atom Hub Switch
# IR G12
# NEO G27 1x
# BUTTON G39
# I2C0 SDA G26 - white
# I2C0 SCL G32
# I2C1 SDA G25 - red
# I2C1 SCL G21
# UART0 RX G3
# UART0 TX G1
# RS485 Rx G33
# RS485 Tx G23
# Relay1 G22
# Relay2 G19
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
i2c:
# - id: i2c0
# sda: 26
+14 -3
View File
@@ -1,4 +1,16 @@
---
# Hardware: Sonoff POW Elite
# Pinout:
# GPIO0 -> reset (binary_sensor gpio)
# GPIO2 -> relay_on (switch gpio)
# GPIO4 -> relay_off (switch gpio)
# GPIO5 -> wifi_status_led (light status_led) (inverted)
# GPIO14 -> tm1621_display (display tm1621 data_pin)
# GPIO16 -> cse7766_uart (uart rx_pin)
# GPIO18 -> led (output ledc) (inverted)
# GPIO25 -> tm1621_display (display tm1621 cs_pin)
# GPIO26 -> tm1621_display (display tm1621 read_pin)
# GPIO27 -> tm1621_display (display tm1621 write_pin)
substitutions:
device: pow-dishwasher
name: Dishwasher POW
@@ -18,11 +30,13 @@ esp32:
framework:
type: esp-idf
advanced:
flash_chip: gd
minimum_chip_revision: 3.1
sram1_as_iram: true
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
uart:
- id: cse7766_uart
@@ -186,6 +200,3 @@ switch:
- delay: 500ms
- switch.turn_off: relay_off # bi-stable relay so no need to keep on
interlock: [relay_on]
time:
- !include common/time/homeassistant.yaml
+14 -4
View File
@@ -1,8 +1,20 @@
---
# Hardware: Sonoff POW Elite
# Pinout:
# GPIO0 -> reset (binary_sensor gpio)
# GPIO2 -> relay_on (switch gpio)
# GPIO4 -> relay_off (switch gpio)
# GPIO5 -> wifi_status_led (light status_led) (inverted)
# GPIO14 -> tm1621_display (display tm1621 data_pin)
# GPIO16 -> cse7766_uart (uart rx_pin)
# GPIO18 -> led (output ledc) (inverted)
# GPIO25 -> tm1621_display (display tm1621 cs_pin)
# GPIO26 -> tm1621_display (display tm1621 read_pin)
# GPIO27 -> tm1621_display (display tm1621 write_pin)
substitutions:
device: pow-washer
name: Washer POW
comment:
comment: "spare"
area: Washroom
update_interval: 10s
@@ -18,6 +30,7 @@ esp32:
framework:
type: esp-idf
advanced:
flash_chip: gd # same device as pow-dishwasher (not read from the device)
minimum_chip_revision: 3.1
sram1_as_iram: true
@@ -186,6 +199,3 @@ switch:
- delay: 500ms
- switch.turn_off: relay_off # bi-stable relay so no need to keep on
interlock: [relay_on]
time:
- !include common/time/homeassistant.yaml
+18 -3
View File
@@ -1,4 +1,15 @@
---
# Hardware: M5Stack ATOM Lite
# Pinout:
# GPIO19 -> spi (spi mosi_pin)
# GPIO21 -> rf_tx (remote_transmitter)
# GPIO22 -> spi (spi miso_pin)
# GPIO23 -> spi (spi clk_pin)
# GPIO25 -> rf_rx (remote_receiver)
# GPIO26 Grove SDA
# GPIO27 NEO (ATOM RGB LED) -> atom_led (status LED, common/status_led_atom.yaml)
# GPIO32 Grove SCL
# GPIO33 -> cc1101 (cc1101 cs_pin)
substitutions:
device: rf
name: RF Bridge
@@ -15,16 +26,20 @@ esp32:
variant: esp32
flash_size: 4MB
framework:
advanced:
flash_chip: gd
type: esp-idf
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
spi:
clk_pin: 23
mosi_pin: 19
miso_pin: 22
cc1101:
cs_pin: 33
frequency: 433.92MHz
@@ -40,7 +55,7 @@ radio_frequency:
id: rf_proxy_rx
remote_receiver_id: rf_rx
frequency: 433.92MHz
remote_receiver:
- id: rf_rx
pin: 25
@@ -55,4 +70,4 @@ remote_transmitter:
- cc1101.begin_tx
on_complete:
then:
- cc1101.begin_rx
- cc1101.begin_rx
+5
View File
@@ -1,4 +1,9 @@
---
# Hardware: Sonoff RF Bridge (obsolete)
# Pinout:
# GPIO4 -> remote_receiver (remote_receiver)
# GPIO5 -> remote_transmitter (remote_transmitter)
# GPIO13 -> status_led (status_led) (inverted)
substitutions:
device: rf433
name: RF433 Bridge
+16 -10
View File
@@ -1,4 +1,16 @@
---
# Hardware: M5Stack M5Stamp S3
# Pinout:
# GPIO0 Button
# GPIO1 I2C SDA -> i2c_rfid (i2c sda)
# GPIO2 I2C SDA, Notify LED -> i2c_rfid (i2c scl)
# GPIO3 -> notify_led (light esp32_rmt_led_strip)
# GPIO4 Buzzer -> buzzer (output ledc)
# GPIO19 U-
# GPIO20 U+
# GPIO21 RGB -> status_led (light esp32_rmt_led_strip)
# I2C:
# 0x24 pn532_module (pn532_i2c)
substitutions:
device: rfid-reader
name: RFID Reader
@@ -31,6 +43,8 @@ esp32:
variant: esp32s3
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
# external_components:
@@ -40,19 +54,11 @@ esp32:
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# logger:
# hardware_uart: UART0
# GPIO20 U+
# GPIO19 U-
# GPIO0 Button
# GPIO1 I2C SDA
# GPIO2 I2C SDA
# GPIO2 Notify LED
# GPIO4 Buzzer
# GPIO21 RGB
api:
actions:
- action: rfidreader_tag_ok
@@ -165,7 +171,7 @@ pn532_i2c:
id(info)="";
if (tag.has_ndef_message()) {
auto message = tag.get_ndef_message();
auto records = message->get_records();
const auto &records = message->get_records();
for (auto &record : records) {
std::string payload = record->get_payload();
std::string type = record->get_type();
+15 -3
View File
@@ -1,4 +1,15 @@
---
# Hardware: M5Stack ATOM Lite + ATOM Hub Switch
# Pinout:
# GPIO19 -> Light (switch gpio)
# GPIO21 -> i2c (i2c scl)
# GPIO22 -> Garden Light (switch gpio)
# GPIO25 -> i2c (i2c sda)
# GPIO26 Grove SDA
# GPIO27 NEO (ATOM RGB LED) -> atom_led (status LED, common/status_led_atom.yaml)
# GPIO32 Grove SCL
# I2C:
# 0x27 pca9554_module (pca9554)
substitutions:
device: shed
name: Shed
@@ -15,12 +26,16 @@ esp32:
variant: esp32
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
type: esp-idf
# version: 5.4.2
# platform_version: 54.03.21
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
i2c:
sda: 25
@@ -108,6 +123,3 @@ switch:
pin:
number: 19
mode: OUTPUT
time:
- !include common/time/homeassistant.yaml
+12 -14
View File
@@ -1,4 +1,15 @@
---
# Hardware: BlitzWolf BW-SHP2/SHP6
# Pinout:
# GPIO0 GPIO_LED1_INV Red LED (inverted), Power Status -> led_red (output gpio)
# GPIO1 GPIO_USER RXD, Optional sensor
# GPIO2 GPIO_LEDLNK_INV Blue LED (inverted), Link Status -> led_blue (output gpio)
# GPIO3 GPIO_USER TXD, Optional sensor
# GPIO5 GPIO_HJL_CF BL0937 or HJL-01 CF power -> sensor/hlw8012 (sensor hlw8012 cf_pin)
# GPIO12 GPIO_NRG_SEL_INV BL0937 or HJL-01 Sel output (0 = Voltage) -> sensor/hlw8012 (sensor hlw8012 sel_pin) (inverted)
# GPIO13 GPIO_KEY1 Button -> Button (binary_sensor gpio) (inverted)
# GPIO14 GPIO_NRG_CF1 BL0937 or HJL-01 CF1 current / voltage -> sensor/hlw8012 (sensor hlw8012 cf1_pin)
# GPIO15 GPIO_REL1 Relay -> Relay (switch gpio)
substitutions:
device: socket-01
name: Socket 01
@@ -19,18 +30,6 @@ esp8266:
packages:
common: !include common/common_esp8266.yaml
# BlitzWolf BW-SHP2 and BW-SHP6 (ESP8285 - BL0937 or HJL-01 Energy Monitoring)
# Pin Name Function
# GPIO15 GPIO_REL1 Relay
# GPIO13 GPIO_KEY1 Button
# GPIO00 GPIO_LED1_INV Red LED (inverted), Power Status
# GPIO02 GPIO_LEDLNK_INV Blue LED (inverted), Link Status
# GPIO05 GPIO_HJL_CF BL0937 or HJL-01 CF power
# GPIO12 GPIO_NRG_SEL_INV BL0937 or HJL-01 Sel output (0 = Voltage)
# GPIO14 GPIO_NRG_CF1 BL0937 or HJL-01 CF1 current / voltage
# GPIO01 GPIO_USER RXD, Optional sensor
# GPIO03 GPIO_USER TXD, Optional sensor
binary_sensor:
- platform: gpio
pin:
@@ -121,8 +120,7 @@ switch:
# number: GPIO00
# inverted: True
time:
- !include common/time/homeassistant.yaml
# time:
# - platform: homeassistant
# timezone: Europe/Bratislava
# on_time:
+12 -14
View File
@@ -1,4 +1,15 @@
---
# Hardware: BlitzWolf BW-SHP2/SHP6
# Pinout:
# GPIO0 GPIO_LED1_INV Red LED (inverted), Power Status -> led_red (output gpio)
# GPIO1 GPIO_USER RXD, Optional sensor
# GPIO2 GPIO_LEDLNK_INV Blue LED (inverted), Link Status -> led_blue (output gpio)
# GPIO3 GPIO_USER TXD, Optional sensor
# GPIO5 GPIO_HJL_CF BL0937 or HJL-01 CF power -> sensor/hlw8012 (sensor hlw8012 cf_pin)
# GPIO12 GPIO_NRG_SEL_INV BL0937 or HJL-01 Sel output (0 = Voltage) -> sensor/hlw8012 (sensor hlw8012 sel_pin) (inverted)
# GPIO13 GPIO_KEY1 Button -> Button (binary_sensor gpio) (inverted)
# GPIO14 GPIO_NRG_CF1 BL0937 or HJL-01 CF1 current / voltage -> sensor/hlw8012 (sensor hlw8012 cf1_pin)
# GPIO15 GPIO_REL1 Relay -> Relay (switch gpio)
substitutions:
device: socket-02
name: Socket 02
@@ -19,18 +30,6 @@ esp8266:
packages:
common: !include common/common_esp8266.yaml
# BlitzWolf BW-SHP2 and BW-SHP6 (ESP8285 - BL0937 or HJL-01 Energy Monitoring)
# Pin Name Function
# GPIO15 GPIO_REL1 Relay
# GPIO13 GPIO_KEY1 Button
# GPIO00 GPIO_LED1_INV Red LED (inverted), Power Status
# GPIO02 GPIO_LEDLNK_INV Blue LED (inverted), Link Status
# GPIO05 GPIO_HJL_CF BL0937 or HJL-01 CF power
# GPIO12 GPIO_NRG_SEL_INV BL0937 or HJL-01 Sel output (0 = Voltage)
# GPIO14 GPIO_NRG_CF1 BL0937 or HJL-01 CF1 current / voltage
# GPIO01 GPIO_USER RXD, Optional sensor
# GPIO03 GPIO_USER TXD, Optional sensor
binary_sensor:
- platform: gpio
pin:
@@ -122,8 +121,7 @@ switch:
on_turn_off:
- light.turn_off: light_red
time:
- !include common/time/homeassistant.yaml
# time:
# - platform: homeassistant
# timezone: Europe/Bratislava
# on_time:
+12 -14
View File
@@ -1,4 +1,15 @@
---
# Hardware: BlitzWolf BW-SHP2/SHP6
# Pinout:
# GPIO0 GPIO_LED1_INV Red LED (inverted), Power Status -> led_red (output gpio)
# GPIO1 GPIO_USER RXD, Optional sensor
# GPIO2 GPIO_LEDLNK_INV Blue LED (inverted), Link Status -> led_blue (output gpio)
# GPIO3 GPIO_USER TXD, Optional sensor
# GPIO5 GPIO_HJL_CF BL0937 or HJL-01 CF power -> sensor/hlw8012 (sensor hlw8012 cf_pin)
# GPIO12 GPIO_NRG_SEL_INV BL0937 or HJL-01 Sel output (0 = Voltage) -> sensor/hlw8012 (sensor hlw8012 sel_pin) (inverted)
# GPIO13 GPIO_KEY1 Button -> Button (binary_sensor gpio) (inverted)
# GPIO14 GPIO_NRG_CF1 BL0937 or HJL-01 CF1 current / voltage -> sensor/hlw8012 (sensor hlw8012 cf1_pin)
# GPIO15 GPIO_REL1 Relay -> Relay (switch gpio)
substitutions:
device: socket-03
name: Socket 03
@@ -25,18 +36,6 @@ esp8266:
packages:
common: !include common/common_esp8266.yaml
# BlitzWolf BW-SHP2 and BW-SHP6 (ESP8285 - BL0937 or HJL-01 Energy Monitoring)
# Pin Name Function
# GPIO15 GPIO_REL1 Relay
# GPIO13 GPIO_KEY1 Button
# GPIO00 GPIO_LED1_INV Red LED (inverted), Power Status
# GPIO02 GPIO_LEDLNK_INV Blue LED (inverted), Link Status
# GPIO05 GPIO_HJL_CF BL0937 or HJL-01 CF power
# GPIO12 GPIO_NRG_SEL_INV BL0937 or HJL-01 Sel output (0 = Voltage)
# GPIO14 GPIO_NRG_CF1 BL0937 or HJL-01 CF1 current / voltage
# GPIO01 GPIO_USER RXD, Optional sensor
# GPIO03 GPIO_USER TXD, Optional sensor
binary_sensor:
- platform: gpio
pin:
@@ -144,8 +143,7 @@ switch:
# number: GPIO00
# inverted: True
time:
- !include common/time/homeassistant.yaml
# time:
# - platform: homeassistant
# timezone: Europe/Bratislava
# on_time:
+67 -11
View File
@@ -1,3 +1,43 @@
# Hardware: M5Stack CoreS3 + Stack-chan kit
# Pinout:
# GPIO0 -> i2s_bus (i2s_audio i2s_mclk_pin)
# GPIO2 -> Camera (esp32_camera)
# GPIO3 -> display_tft (display mipi_spi cs_pin)
# GPIO5 -> ir_tx (remote_transmitter)
# GPIO6 -> uart_servo (uart tx_pin)
# GPIO7 -> uart_servo (uart rx_pin)
# GPIO10 -> ir_rx (remote_receiver)
# GPIO11 -> i2c_bsp (i2c scl)
# GPIO12 -> i2c_bsp (i2c sda)
# GPIO13 -> speaker_id (speaker i2s_audio i2s_dout_pin)
# GPIO14 -> stackchan_microphone (microphone i2s_audio i2s_din_pin)
# GPIO15 -> Camera (esp32_camera data_pins)
# GPIO16 -> Camera (esp32_camera data_pins)
# GPIO33 -> i2s_bus (i2s_audio i2s_lrclk_pin)
# GPIO34 -> i2s_bus (i2s_audio i2s_bclk_pin)
# GPIO35 -> display_tft (display mipi_spi dc_pin)
# GPIO36 -> spi_bus (spi clk_pin)
# GPIO37 -> spi_bus (spi mosi_pin)
# GPIO38 -> Camera (esp32_camera href_pin)
# GPIO39 -> Camera (esp32_camera data_pins)
# GPIO40 -> Camera (esp32_camera data_pins)
# GPIO41 -> Camera (esp32_camera data_pins)
# GPIO42 -> Camera (esp32_camera data_pins)
# GPIO45 -> Camera (esp32_camera pixel_clock_pin)
# GPIO46 -> Camera (esp32_camera vsync_pin)
# GPIO47 -> Camera (esp32_camera data_pins)
# GPIO48 -> Camera (esp32_camera data_pins)
# I2C:
# 0x23 sensor ltr_als_ps (sensor ltr_als_ps)
# 0x34 axp2101_pmu (axp2101)
# 0x36 aw88298_dac (audio_dac aw88298)
# 0x38 touch_lcd (touchscreen ft63x6)
# 0x40 es7210_adc (audio_adc es7210)
# 0x41 sensor ina226 (sensor ina226)
# 0x51 rtc_time (time bm8563)
# 0x58 aw9523b_hub (aw9523b)
# 0x68 touch_hub (si12t)
# 0x6F m5ioe1_hub (m5ioe1)
substitutions:
device: stackchan
name: StackChan
@@ -25,6 +65,8 @@ esp32:
flash_size: 16MB
toolchain: esp-idf
framework:
advanced:
flash_chip: generic
type: esp-idf
psram:
@@ -33,6 +75,7 @@ psram:
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
external_components:
- source: github://m5stack/esphome-yaml/components
@@ -40,7 +83,7 @@ external_components:
refresh: 0s
- source: github://randybb/esphome-components
components: [audio_spectrum]
refresh: 1d
refresh: 1h
globals:
- id: in_love
@@ -464,9 +507,9 @@ spi:
image:
- platform: file
file: assets/images/esphome-logo-text-on-dark.svg
file: assets/images/made-for-esphome-white-on-black.svg
id: esphome_logo
resize: 280x56
resize: 230x68
type: RGB565
transparency: alpha_channel
- platform: file
@@ -545,22 +588,36 @@ display:
if (id(show_status)) {
first_draw = true;
it.fill(id(face_bg));
it.image(160, 45, id(esphome_logo), ImageAlign::CENTER);
it.image(160, 46, id(esphome_logo), ImageAlign::CENTER);
it.print(160, 95, id(font_title), id(face_fg), TextAlign::CENTER, "${name}");
if (wifi_ok) {
it.printf(20, 135, id(font_status), id(status_ok), "WiFi: %s (%d dBm)",
id(ip_address_sensor).state.c_str(), rssi);
it.printf(20, 114, id(font_status), id(status_ok), "WiFi: connected (%d dBm)", rssi);
// one global IPv6 (skip link-local) and one IPv4 address
int y = 133;
char buf[network::IP_ADDRESS_BUFFER_SIZE];
for (bool v6 : {true, false}) {
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) {
if (!ip.is_set() || ip.is_ip6() != v6)
continue;
ip.str_to(buf);
if (v6 && strncmp(buf, "fe80", 4) == 0)
continue;
it.print(30, y, id(font_status), id(status_dim), buf);
y += 19;
break;
}
}
} else {
it.print(20, 135, id(font_status), id(status_wait), "WiFi: connecting...");
it.print(20, 114, id(font_status), id(status_wait), "WiFi: connecting...");
}
const bool api_ok = api::global_api_server->is_connected();
it.print(20, 162, id(font_status), api_ok ? id(status_ok) : id(status_wait),
it.print(20, 172, id(font_status), api_ok ? id(status_ok) : id(status_wait),
api_ok ? "Home Assistant: connected" : "Home Assistant: waiting...");
if (batt >= 0) {
it.printf(20, 189, id(font_status), batt <= 20 && !charging ? id(status_low) : id(status_dim),
it.printf(20, 191, id(font_status), batt <= 20 && !charging ? id(status_low) : id(status_dim),
"Battery: %d%%%s", batt, charging ? " (charging)" : "");
}
it.printf(20, 212, id(font_status), id(status_dim), "ESPHome %s", ESPHOME_VERSION);
@@ -867,7 +924,7 @@ light:
name: LCD Backlight
output: lcd_backlight_output
restore_mode: ALWAYS_ON
remote_transmitter:
id: ir_tx
pin: 5
@@ -883,4 +940,3 @@ time:
id: rtc_time
i2c_id: i2c_bsp
update_interval: never
- !include common/time/homeassistant.yaml
+4
View File
@@ -1,4 +1,8 @@
---
# Hardware: Sonoff Mini
# Pinout:
# GPIO12 -> relay (output gpio)
# GPIO13 -> led_blue (output gpio)
substitutions:
device: staircase-light
name: Staircase
+243 -79
View File
@@ -1,4 +1,14 @@
---
# Hardware: M5Stack M5Stamp C3
# Pinout:
# GPIO0 Grove SCL -> touchscreen/xpt2046 (touchscreen xpt2046 cs_pin)
# GPIO1 Grove SDA -> touchscreen/xpt2046 (touchscreen xpt2046 interrupt_pin)
# GPIO4 -> spi (spi clk_pin)
# GPIO5 -> spi (spi mosi_pin)
# GPIO6 -> spi (spi miso_pin)
# GPIO7 -> main_display (display mipi_spi cs_pin)
# GPIO8 -> main_display (display mipi_spi dc_pin)
# GPIO10 -> main_display (display mipi_spi reset_pin)
substitutions:
device: tft
name: TFT
@@ -10,104 +20,258 @@ esphome:
friendly_name: ${name}
area: ${area}
comment: ${comment}
platformio_options:
board_build.flash_mode: dio
on_boot:
- priority: -100
then:
- lvgl.page.show: status_page
esp32:
variant: esp32c3
framework:
advanced:
flash_chip: generic
type: esp-idf
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
logger:
logs:
component: ERROR
# GPIO1 UART TX
# GPIO3 UART RX
# GPIO4 I2C SDA
# GPIO5 I2C SCL
# GPIO12 DISPLAY DIO
# GPIO12 DISPLAY CLOCK
# GPIO14 BUZZER
# GPIO16 RGB
api:
# status page until Home Assistant connects (log viewers don't subscribe to states)
on_client_connected:
- delay: 2s
- if:
condition:
api.connected:
state_subscription_only: true
then:
- lvgl.page.show: main_page
on_client_disconnected:
- if:
condition:
not:
api.connected:
state_subscription_only: true
then:
- lvgl.page.show: status_page
spi:
clk_pin: 4
mosi_pin: 5
miso_pin: 6
color:
- id: my_green
hex: 00ff00
- id: my_magenta
hex: ff00ff
- id: my_red
hex: ff0000
- id: my_white
hex: ffffff
font:
- file: "gfonts://Roboto"
id: font_default
size: 20
- file: "gfonts://B612"
id: b612_24
size: 24
- file: "gfonts://B612"
id: b612_16
size: 16
- file: "gfonts://B612"
id: b612_12
size: 12
- file: "gfonts://B612 Mono"
id: b612_24_mono
size: 24
- file: "gfonts://B612 Mono"
id: b612_16_mono
size: 16
- file: "gfonts://B612 Mono"
id: b612_12_mono
size: 12
- file: "gfonts://Roboto"
id: roboto_32
size: 32
- file: "gfonts://Roboto"
id: roboto_24
size: 24
- file: "gfonts://Roboto"
id: roboto_16
size: 16
- file: "gfonts://Roboto"
id: roboto_12
size: 12
- file: "gfonts://Roboto Mono"
id: roboto_32_mono
size: 32
- file: "gfonts://Roboto Mono"
id: roboto_24_mono
size: 24
- file: "gfonts://Roboto Mono"
id: roboto_16_mono
size: 16
- file: "gfonts://Roboto Mono"
id: roboto_12_mono
size: 12
display:
- platform: mipi_spi
id: main_display
model: ILI9341
cs_pin: 7
dc_pin: 8
reset_pin: 10
invert_colors: false
lambda: |-
it.fill(Color::BLACK);
it.print(0, 0, id(b612_12), id(my_white), TextAlign::TOP_LEFT, "HELLO WORLD!");
it.print(0, 14, id(b612_12), id(my_green), TextAlign::TOP_LEFT, "HELLO WORLD!");
it.print(0, 28, id(b612_12), id(my_magenta), TextAlign::TOP_LEFT, "HELLO WORLD!");
it.print(0, 42, id(b612_12), id(my_red), TextAlign::TOP_LEFT, "HELLO WORLD!");
data_rate: 40MHz
update_interval: never
auto_clear_enabled: false
touchscreen:
- platform: xpt2046
display: main_display
cs_pin: 0
interrupt_pin: 1
transform:
mirror_x: true
calibration:
x_min: 330
x_max: 3620
y_min: 230
y_max: 3680
script:
- id: update_status
then:
- lambda: |-
// same colors as the other status screens: ok green, waiting orange, details gray
static const uint32_t OK = 0x4DD966, WAIT = 0xFFB300;
auto set = [](lv_obj_t *label, const std::string &text, uint32_t color) {
lv_label_set_text(label, text.c_str());
lv_obj_set_style_text_color(label, lv_color_hex(color), LV_PART_MAIN);
};
const bool wifi_ok = wifi::global_wifi_component->is_connected();
set(id(status_wifi),
wifi_ok ? str_sprintf("WiFi: connected (%d dBm)", wifi::global_wifi_component->wifi_rssi())
: std::string("WiFi: connecting..."),
wifi_ok ? OK : WAIT);
// IPv6 first (skip link-local), then IPv4
std::string ips;
if (wifi_ok) {
char buf[network::IP_ADDRESS_BUFFER_SIZE];
for (bool v6 : {true, false}) {
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) {
if (!ip.is_set() || ip.is_ip6() != v6)
continue;
ip.str_to(buf);
if (v6 && strncmp(buf, "fe80", 4) == 0)
continue;
if (!ips.empty())
ips += "\n";
ips += buf;
}
}
}
lv_label_set_text(id(status_ips), ips.c_str());
if (ips.empty())
lv_obj_add_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
else
lv_obj_remove_flag(id(status_ips), LV_OBJ_FLAG_HIDDEN);
const bool api_ok = api::global_api_server->is_connected();
set(id(status_ha), api_ok ? "Home Assistant: connected" : "Home Assistant: waiting...",
api_ok ? OK : WAIT);
const uint32_t up = millis() / 1000;
lv_label_set_text(id(status_footer),
str_sprintf("ESPHome %s\nup %ud %02u:%02u:%02u", ESPHOME_VERSION, up / 86400,
(up / 3600) % 24, (up / 60) % 60, up % 60).c_str());
interval:
- interval: 1s
then:
- lvgl.label.update:
id: clock_label
text: !lambda |-
auto now = id(ha_time).now();
if (!now.is_valid())
return std::string("--:--");
return now.strftime("%H:%M");
- if:
condition:
lvgl.page.is_showing: status_page
then:
- script.execute: update_status
image:
- platform: file
file: assets/images/made-for-esphome-white-on-black.svg
id: esphome_logo
resize: 220x65
type: RGB565
transparency: alpha_channel
font:
- file: "gfonts://Roboto@500"
id: font_clock
size: 80
glyphs: "0123456789:-"
- file: "gfonts://Roboto"
id: font_title
size: 24
- file: "gfonts://Roboto"
id: font_status
size: 14
lvgl:
log_level: WARN
color_depth: 16
bg_color: 0x000000
text_color: 0xFFFFFF
theme:
button:
bg_color: 0x2B2F36
radius: 12
checked:
bg_color: 0xE08A00
buttonmatrix:
bg_opa: TRANSP
border_width: 0
items:
bg_color: 0x2B2F36
text_color: 0xFFFFFF
radius: 12
checked:
bg_color: 0xE08A00
top_layer:
widgets:
# same navigation bar as on the other LVGL displays
- buttonmatrix:
id: nav_bar
align: bottom_mid
width: 100%
height: 48
pad_all: 4
pad_column: 6
items:
text_font: montserrat_20
rows:
- buttons:
- id: page_prev
text: ""
on_press:
then:
lvgl.page.previous:
- id: page_home
text: ""
on_press:
then:
lvgl.page.show: main_page
- id: page_next
text: ""
on_press:
then:
lvgl.page.next:
pages:
# 1: clock
- id: main_page
widgets:
- label:
id: clock_label
align: CENTER
y: -24
text_font: font_clock
text: "--:--"
# 2: status (shown until Home Assistant connects)
- id: status_page
on_load:
- script.execute: update_status
widgets:
- image:
src: esphome_logo
align: TOP_MID
y: 8
- label:
align: TOP_MID
y: 78
text_font: font_title
text: "${name}"
- obj:
x: 8
y: 116
width: 224
height: SIZE_CONTENT
bg_opa: TRANSP
border_width: 0
pad_all: 0
scrollbar_mode: "OFF"
layout:
type: flex
flex_flow: column
pad_row: 6
widgets:
- label:
id: status_wifi
text_font: font_status
text: ""
- label:
id: status_ips
text_font: font_status
text_color: 0x8C8C8C
text: ""
- label:
id: status_ha
text_font: font_status
text: ""
- label:
id: status_footer
text_font: font_status
text_color: 0x8C8C8C
text: ""
+1
View File
@@ -1,4 +1,5 @@
---
# Hardware: LilyGO T-PCIE
substitutions:
device: tracker
name: Tracker
+18 -10
View File
@@ -1,4 +1,22 @@
---
# Hardware: Huacanxing H801
# Pinout:
# # H801 LED module
# Function Pin Channel
# R GPIO15 PWM1
# G GPIO13 PWM2
# B GPIO12 PWM3
# W1 GPIO14 PWM4
# W2 GPIO04 PWM5
# LED D1 R GPIO05
# LED D2 G GPIO01
# Used:
# GPIO4 pwm_warm_white (output esp8266_pwm)
# GPIO5 status_led_id (light status_led)
# GPIO12 pwm_blue (output esp8266_pwm)
# GPIO13 pwm_green (output esp8266_pwm)
# GPIO14 pwm_cold_white (output esp8266_pwm)
# GPIO15 pwm_red (output esp8266_pwm)
substitutions:
device: tv-light
name: TV Light
@@ -17,16 +35,6 @@ esp8266:
packages:
common: !include common/common_esp8266.yaml
## H801 LED module
# Function Pin Channel
# R GPIO15 PWM1
# G GPIO13 PWM2
# B GPIO12 PWM3
# W1 GPIO14 PWM4
# W2 GPIO04 PWM5
# LED D1 R GPIO05
# LED D2 G GPIO01
light:
- platform: status_led
id: status_led_id
+2
View File
@@ -1,4 +1,6 @@
---
# Hardware: M5Stack ATOM Lite
# Pinout: see common/vehicle_base.yaml
substitutions:
device: vehicle-honda-pcx125
name: Vehicle Honda PCX125
+2
View File
@@ -1,4 +1,6 @@
---
# Hardware: M5Stack ATOM Lite
# Pinout: see common/vehicle_base.yaml
substitutions:
device: vehicle-suzuki-dl650
name: Vehicle Suzuki DL650
+2
View File
@@ -1,4 +1,6 @@
---
# Hardware: M5Stack ATOM Lite
# Pinout: see common/vehicle_base.yaml
substitutions:
device: vehicle-toyota-auris-ts
name: Vehicle Toyota Auris TS
+2
View File
@@ -1,4 +1,6 @@
---
# Hardware: M5Stack ATOM Lite
# Pinout: see common/vehicle_base.yaml
substitutions:
device: vehicle-toyota-yaris-cross
name: Vehicle Toyota Yaris Cross
+7 -7
View File
@@ -1,4 +1,11 @@
---
# Hardware: Sonoff Basic R2
# Pinout:
# GPIO0 BUTTON -> Button (binary_sensor gpio) (inverted)
# GPIO1 TX PIN
# GPIO3 RX PIN
# GPIO12 RELAY -> Relay (switch gpio)
# GPIO13 LED1 -> led (output gpio)
substitutions:
device: waterproof-socket
name: Waterproof Socket
@@ -17,13 +24,6 @@ esp8266:
packages:
common: !include common/common_esp8266.yaml
# Sonoff Basic R2
# GPIO00 - BUTTON
# GPIO12 - RELAY
# GPIO13 - LED1
# GPIO03 - RX PIN
# GPIO01 - TX PIN
binary_sensor:
- platform: gpio
pin:
+14 -3
View File
@@ -1,4 +1,15 @@
---
# Hardware: M5Stack ATOM Lite + ATOM Hub Switch
# Pinout:
# GPIO21 -> i2c (i2c scl)
# GPIO23 -> modbus_uart (uart tx_pin)
# GPIO25 -> i2c (i2c sda)
# GPIO26 Grove SDA
# GPIO27 NEO (ATOM RGB LED) -> atom_led (status LED, common/status_led_atom.yaml)
# GPIO32 Grove SCL
# GPIO33 -> modbus_uart (uart rx_pin)
# I2C:
# 0x27 relay_module (pca9554)
substitutions:
device: well
name: Well
@@ -30,10 +41,13 @@ esp32:
framework:
type: esp-idf
advanced:
flash_chip: gd
sram1_as_iram: true
packages:
common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
api:
actions:
@@ -357,6 +371,3 @@ valve:
- switch.turn_on: irrigation_relay_8
close_action:
- switch.turn_off: irrigation_relay_8
time:
- !include common/time/homeassistant.yaml
+3
View File
@@ -1,6 +1,9 @@
wifi_ssid: "ssid"
wifi_password: "password"
wifi_ssid_ipv6: "ssid"
wifi_password_ipv6: "password"
api_password: "password"
api_key: "oSsCFxRUqIJLpT98cQwSwNxYoC7zbUh0YBHczAWRyBI="