Compare commits

...
67 Commits
Author SHA1 Message Date
randy 4c45ebdc4a all esp32: disable wifi power saving
CI / YAML lint (push) Successful in 8s
CI / ESPHome config validation (push) Successful in 1m2s
2026-10-08 22:52:25 +02:00
randy 2ad74b9d05 all esp8266: switch to native toolchain 2026-10-08 22:51:21 +02:00
randy b1b57818df fireplace, heater: switch to native ds248x component + cleanup 2026-10-08 22:50:00 +02:00
randy 1a83052d90 Spool reader: Creality CFS tags too
CI / YAML lint (push) Successful in 9s
CI / ESPHome config validation (push) Successful in 57s
creality_cfs reads the Creality tags of the spools, sends their record
to Home Assistant (esphome.creality_cfs) and writes them through the
creality_cfs_write action; the success tune gets a valid default
duration.
2026-10-05 21:22:36 +02:00
randy 8eae480253 OpenPrintTag reader: pn5180 and openprinttag components, red flash on writes
CI / YAML lint (push) Failing after 17s
CI / ESPHome config validation (push) Successful in 55s
The reader config follows the split of pn5180 into the reader and the
openprinttag component; the notify LED flashes red while the
integration writes to a tag.
2026-10-03 18:18:42 +02:00
randy 5fdacb82df OpenPrintTag reader: aux write action for the integration
CI / YAML lint (push) Failing after 17s
CI / ESPHome config validation (push) Successful in 51s
openprinttag_write_aux lets the OpenPrintTag integration's
openprinttag.update write the consumed weight and other aux values
to the tag on the reader.
2026-10-03 13:55:21 +02:00
randy 9eb5cd9155 OpenPrintTag reader: send the tag record to Home Assistant
esphome.openprinttag event with the uid and the raw record (empty when
the tag is removed) for the OpenPrintTag integration
(randybb/ha-openprinttag).
2026-10-03 13:20:40 +02:00
randy b8f8649833 OpenPrintTag reader: M5Stamp S3 with a PN5180
Filament spool tags to Home Assistant through the pn5180 component of
randybb/esphome-components, the color also as a light. Onboard LED for
tag feedback and status until the external LED is fitted, buzzer on
GPIO4.
2026-10-03 12:48:56 +02:00
randy 5fdea643a7 rfid-reader: use a valid RTTTL default duration (d=32)
ESPHome only accepts d=1/2/4/8/16/32 now; d=24 was rejected and the
success/write tones never played.
2026-10-03 10:51:23 +02:00
randy 4bbf26fc87 Update comment about upstream mdns component
CI / YAML lint (push) Failing after 17s
CI / ESPHome config validation (push) Successful in 1m0s
2026-10-02 17:46:59 +02:00
randy 427e9ac136 IPv6-only for the Ethernet gateway
Split the WiFi part off common/ipv6_only.yaml into common/ipv6_only_eth.yaml
and use it on mcu-gateway. The #19750 component list needs ethernet,
otherwise the stock component still runs DHCPv4. mdns from the fork also
carries the IPv6 fix for ETH-only builds (espressif/esp-protocols#1161).
2026-10-01 23:49:02 +02:00
randy 005c9903bf Disable api reboot timeout for kitchen lights due flaky wifi (thanks ubiquiti!)
CI / YAML lint (push) Failing after 17s
CI / ESPHome config validation (push) Successful in 51s
2026-10-01 12:37:09 +02:00
randy db57574497 Fix crashing, display cs and fonts for cnc pendant
CI / YAML lint (push) Failing after 18s
CI / ESPHome config validation (push) Successful in 49s
2026-10-01 01:38:21 +02:00
randy fd7a4c98b5 Add initial mcu-cnc-pendant configuration 2026-10-01 00:50:41 +02:00
randy 2e8b678072 nrf-ant, nrf-dk: two-way UART on the DK default pins, wires crossed
Both boards use UART1 RX P1.01 / TX P1.02 so Home Assistant data can reach
the ANT+ node's transmitters; on the default pins the ANT+ node no longer
needs the RX pin workaround.
2026-09-30 23:15:10 +02:00
randy 3f9a8c3117 nrf-ant: Garmin HRM-Dual, HRM-Tri, Rally RS200, Speed Sensor 2, SRAM Force AXS
CI / YAML lint (push) Successful in 8s
CI / ESPHome config validation (push) Successful in 50s
Also sets the unused UART1 RX to P1.02: without it the fork keeps the DK's
default RX pin, P1.01, and the UART hears its own transmissions.
2026-09-30 22:13:33 +02:00
randy 38ede7fab6 nrf-ant: Garmin HRM-Pro, Concept2 PM5, Garmin Tempe, Garmin Varia RTL515, status LEDs
LED 1 lights while a configured ANT+ device is received, LED 2 while an
unconfigured one is in range; everything is forwarded to mcu-nrf-dk.
2026-09-30 21:55:04 +02:00
randy ad9aeea346 nrf-dk: Thread MTD, frees 52 KB of the MCUboot slot (98 % -> 87 %) 2026-09-30 21:34:17 +02:00
randy 3a397cfb4b ANT+ via ESPHome: mcu-nrf-ant (RadiANT) sends heart rate to mcu-nrf-dk over packet_transport
Replaces the E73 running the archived nrf-ant-bridge firmware and drops
mcu-ant-host, which read that bridge's line protocol.
2026-09-30 21:17:20 +02:00
randy 6fd5ee1fa7 Add ant-host: host ESPHome reading an ANT+ bridge over serial 2026-09-30 20:07:57 +02:00
randy eb25302e9b nrf-dk: Thread, buttons, LEDs and ANT+ heart rate from the E73 bridge 2026-09-30 20:07:57 +02:00
randy 34929a38c7 CI: skip zephyr: configs, they need the esphomeplatformzephyr fork 2026-09-30 20:07:57 +02:00
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
93 changed files with 120274 additions and 2093 deletions

No files matched your search

+18 -9
View File
@@ -10,35 +10,42 @@ jobs:
name: YAML lint name: YAML lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v7
- name: Get changed YAML files - name: Get changed YAML files
id: changed id: changed
uses: tj-actions/changed-files@v46 uses: tj-actions/changed-files@v47
with: with:
files: "**/*.yaml" 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' if: steps.changed.outputs.any_changed == 'true'
with: env:
config_file: .yamllint.yml PIP_BREAK_SYSTEM_PACKAGES: "1"
file_or_dir: ${{ steps.changed.outputs.all_changed_files }} run: |
pip install --ignore-installed yamllint
yamllint -c .yamllint.yml -f parsable ${{ steps.changed.outputs.all_changed_files }}
validate: validate:
name: ESPHome config validation name: ESPHome config validation
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v7
- name: Get changed device configs - name: Get changed device configs
id: changed id: changed
uses: tj-actions/changed-files@v46 uses: tj-actions/changed-files@v47
with: with:
files: "mcu-*.yaml" files: "mcu-*.yaml"
- name: Install ESPHome (dev) - name: Install ESPHome (dev)
if: steps.changed.outputs.any_changed == 'true' 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 - name: Prepare secrets
if: steps.changed.outputs.any_changed == 'true' if: steps.changed.outputs.any_changed == 'true'
@@ -48,6 +55,8 @@ jobs:
if: steps.changed.outputs.any_changed == 'true' if: steps.changed.outputs.any_changed == 'true'
run: | run: |
for f in ${{ steps.changed.outputs.all_changed_files }}; do for f in ${{ steps.changed.outputs.all_changed_files }}; do
# zephyr: needs the esphomeplatformzephyr fork, upstream doesn't know it yet
if grep -q '^zephyr:' "$f"; then echo "Skipping $f (zephyr fork)"; continue; fi
echo "Validating $f..." echo "Validating $f..."
esphome config "$f" esphome config "$f"
done done
+1 -1
View File
@@ -2,7 +2,7 @@
# This is an example and may include too much for your use-case. # This is an example and may include too much for your use-case.
# You can modify this file to suit your needs. # You can modify this file to suit your needs.
/.claude/ /.claude/
/.esphome/ .esphome/
/secrets.yaml /secrets.yaml
/archive/ /archive/
/trash/ /trash/
+4
View File
@@ -25,3 +25,7 @@ rules:
comments: comments:
require-starting-space: false require-starting-space: false
# Aligned values (e.g. the bedroom lamp presets) are intentional
colons:
max-spaces-after: -1
+28781
View File
File diff suppressed because it is too large. Load diff
+86576
View File
File diff suppressed because it is too large. Load diff
@@ -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/uptime.yaml
- <<: !include text_sensor/wifi_info.yaml - <<: !include text_sensor/wifi_info.yaml
# time: time:
#. - <<: !include time/homeassistant.yaml - <<: !include time/homeassistant.yaml
network: network:
enable_ipv6: true enable_ipv6: true
+3
View File
@@ -24,5 +24,8 @@ text_sensor:
- <<: !include text_sensor/version.yaml - <<: !include text_sensor/version.yaml
- <<: !include text_sensor/wifi_info.yaml - <<: !include text_sensor/wifi_info.yaml
time:
- <<: !include time/homeassistant.yaml
network: network:
enable_ipv6: true enable_ipv6: true
+3
View File
@@ -23,5 +23,8 @@ text_sensor:
- <<: !include text_sensor/version.yaml - <<: !include text_sensor/version.yaml
- <<: !include text_sensor/wifi_info.yaml - <<: !include text_sensor/wifi_info.yaml
time:
- <<: !include time/homeassistant.yaml
network: network:
enable_ipv6: true enable_ipv6: true
+3
View File
@@ -21,5 +21,8 @@ text_sensor:
- <<: !include text_sensor/version.yaml - <<: !include text_sensor/version.yaml
- <<: !include text_sensor/ethernet_info.yaml - <<: !include text_sensor/ethernet_info.yaml
time:
- <<: !include time/homeassistant.yaml
network: network:
enable_ipv6: true enable_ipv6: true
+3
View File
@@ -27,3 +27,6 @@ text_sensor:
- <<: !include text_sensor/git_ref.yaml - <<: !include text_sensor/git_ref.yaml
- <<: !include text_sensor/version.yaml - <<: !include text_sensor/version.yaml
- <<: !include text_sensor/wifi_info.yaml - <<: !include text_sensor/wifi_info.yaml
time:
- <<: !include time/homeassistant.yaml
+14
View File
@@ -0,0 +1,14 @@
---
# 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
# Ethernet devices use common/ipv6_only_eth.yaml (this without the WiFi part)
packages:
base: !include ipv6_only_eth.yaml
wifi:
networks:
- id: !extend wifi_iot
ssid: !secret wifi_ssid_ipv6
password: !secret wifi_password_ipv6
+30
View File
@@ -0,0 +1,30 @@
---
# IPv6-only IoT network (SLAAC, no DHCPv4) for ethernet devices; add next to a common package:
# packages:
# common_eth: !include common/common_eth.yaml
# ipv6_only: !include common/ipv6_only_eth.yaml
# WiFi devices use common/ipv6_only.yaml (this + the IPv6 SSID)
external_components:
# network enable_ipv4 + audio HTTP reader over IPv6 (esphome/esphome#19750), drop once merged
- source: github://pr#19750
components: [const, network, wifi, ethernet, audio]
esp32:
framework:
components:
# mdns 1.12.0 + fix for "A 0.0.0.0" without IPv4 (espressif/esp-protocols#1156, merged)
# + IPv6 on ETH-only builds (espressif/esp-protocols#1161, merged), drop once both are 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: ota:
- platform: esphome - platform: esphome
password: !secret ota_password 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: ota:
- platform: esphome - platform: esphome
id: ota_esphome
password: !secret ota_password 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 allow_partition_access: true
-1
View File
@@ -7,4 +7,3 @@ accuracy_decimals: 2
update_interval: 60s update_interval: 60s
filters: filters:
- lambda: return x / 86400; - 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
+2
View File
@@ -2,6 +2,8 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd # ESP32-PICO-D4, like every other ATOM Lite
type: esp-idf type: esp-idf
external_components: external_components:
+4 -1
View File
@@ -2,8 +2,11 @@
wifi: wifi:
# reboot_timeout: 0s # reboot_timeout: 0s
networks: 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 password: !secret wifi_password
enable_btm: true enable_btm: true
enable_rrm: true enable_rrm: true
min_auth_mode: WPA3 min_auth_mode: WPA3
power_save_mode: none
+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
+148
View File
@@ -0,0 +1,148 @@
#pragma once
// Moonraker client for mcu-cnc-pendant on its own FreeRTOS task: esp_http_client blocks
// (DNS is not bounded by timeout_ms), so the main loop only queues commands and reads
// the last polled status. An unreachable Klipper shows as "offline" instead of starving
// the loop into the task watchdog.
#include <deque>
#include <mutex>
#include <string>
#include "esp_http_client.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esphome/components/json/json_util.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
namespace moonraker {
struct Status {
float pos[3]{};
std::string homed;
std::string state{"offline"};
};
class Client {
public:
void start(const char *base) {
this->base_ = base;
xTaskCreate(task, "moonraker", 6144, this, 1, nullptr);
}
// Run G-code; dropped when Klipper is not keeping up.
void gcode(const std::string &script) {
JsonDocument doc;
doc["script"] = script;
std::string body;
serializeJson(doc, body);
this->post("/printer/gcode/script", body);
}
// urgent: throw away everything queued and send this first (emergency stop)
void post(const std::string &path, const std::string &body = "", bool urgent = false) {
std::lock_guard<std::mutex> lock(this->mutex_);
if (urgent) {
this->queue_.clear();
} else if (this->queue_.size() >= MAX_QUEUE) {
return;
}
this->queue_.emplace_back(path, body);
}
Status status() {
std::lock_guard<std::mutex> lock(this->mutex_);
return this->status_;
}
protected:
static constexpr size_t MAX_QUEUE = 8;
static constexpr uint32_t POLL_MS = 250;
static constexpr int TIMEOUT_MS = 1000;
static void task(void *arg) {
auto *self = static_cast<Client *>(arg);
uint32_t last_poll = 0;
for (;;) {
std::pair<std::string, std::string> cmd;
bool have_cmd = false;
{
std::lock_guard<std::mutex> lock(self->mutex_);
if (!self->queue_.empty()) {
cmd = std::move(self->queue_.front());
self->queue_.pop_front();
have_cmd = true;
}
}
if (have_cmd) {
int code = self->request(cmd.first, &cmd.second, nullptr);
if (code != 200)
ESP_LOGW("moonraker", "POST %s failed (%d): %s", cmd.first.c_str(), code, cmd.second.c_str());
continue; // drain commands before the next poll
}
if (esphome::millis() - last_poll >= POLL_MS) {
last_poll = esphome::millis();
self->poll();
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void poll() {
std::string body;
Status s;
if (this->request("/printer/objects/query?gcode_move=gcode_position&toolhead=homed_axes&print_stats=state",
nullptr, &body) == 200) {
auto doc = esphome::json::parse_json(body);
JsonObject st = doc["result"]["status"];
JsonArray p = st["gcode_move"]["gcode_position"];
for (int i = 0; i < 3; i++)
s.pos[i] = p[i];
s.homed = st["toolhead"]["homed_axes"].as<std::string>();
s.state = st["print_stats"]["state"].as<std::string>();
} else {
std::lock_guard<std::mutex> lock(this->mutex_);
s.pos[0] = this->status_.pos[0]; // keep the last position, only flag offline
s.pos[1] = this->status_.pos[1];
s.pos[2] = this->status_.pos[2];
}
std::lock_guard<std::mutex> lock(this->mutex_);
this->status_ = std::move(s);
}
// POST when body is set, GET otherwise; returns the HTTP status or -1
int request(const std::string &path, const std::string *body, std::string *out) {
std::string url = this->base_ + path;
esp_http_client_config_t cfg{};
cfg.url = url.c_str();
cfg.timeout_ms = TIMEOUT_MS;
cfg.method = body ? HTTP_METHOD_POST : HTTP_METHOD_GET;
esp_http_client_handle_t c = esp_http_client_init(&cfg);
if (c == nullptr)
return -1;
int code = -1;
int len = body ? body->size() : 0;
if (len > 0)
esp_http_client_set_header(c, "Content-Type", "application/json");
if (esp_http_client_open(c, len) == ESP_OK && (len == 0 || esp_http_client_write(c, body->data(), len) == len)) {
esp_http_client_fetch_headers(c);
code = esp_http_client_get_status_code(c);
char buf[256];
int n;
while (out != nullptr && (n = esp_http_client_read(c, buf, sizeof(buf))) > 0)
out->append(buf, n);
}
esp_http_client_cleanup(c);
return code;
}
std::string base_;
std::mutex mutex_;
std::deque<std::pair<std::string, std::string>> queue_;
Status status_;
};
inline Client client;
} // namespace moonraker
+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: substitutions:
device: air-office-r device: air-office-r
name: Office R Air name: Office R Air
@@ -16,10 +24,16 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
status_led: !include
file: common/status_led.yaml
vars:
light_id: neo
i2c: i2c:
# - id: i2c0 # - id: i2c0
@@ -46,20 +60,13 @@ uart:
# inverted: true # inverted: true
light: light:
- platform: esp32_rmt_led_strip # also the status light (common/status_led.yaml): back to its previous state when all is fine
# name: LED
id: neo
channel_colors: GRB
pin: 27
num_leds: 1
chipset: ws2812
restore_mode: ALWAYS_OFF
- platform: esp32_rmt_led_strip - platform: esp32_rmt_led_strip
name: NEO name: NEO
id: neo_strip id: neo
channel_colors: GRB channel_colors: GRB
pin: 25 pin: 25
num_leds: 7 num_leds: 7 # 8 on the stick, the 8th one is hidden
chipset: ws2812 chipset: ws2812
restore_mode: ALWAYS_OFF restore_mode: ALWAYS_OFF
effects: effects:
+12
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: substitutions:
device: apollo-dev #test device: apollo-dev #test
name: Apollo DEV #test name: Apollo DEV #test
@@ -16,6 +26,8 @@ esp32:
flash_size: 8MB flash_size: 8MB
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: generic
type: esp-idf type: esp-idf
packages: packages:
+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: substitutions:
device: atoms3 device: atoms3
name: AtomS3 name: AtomS3
@@ -23,6 +42,8 @@ esp32:
flash_size: 8MB flash_size: 8MB
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
ota: ota:
@@ -33,12 +54,14 @@ pcf8574:
address: 0x21 address: 0x21
pcf8575: true pcf8575: true
animation: image:
- file: "assets/images/blinky.gif" - platform: animation
file: "assets/images/blinky.gif"
id: blinky id: blinky
resize: 128x128 resize: 128x128
type: RGB565 type: RGB565
- file: "assets/images/vault_boy_walking.gif" - platform: animation
file: "assets/images/vault_boy_walking.gif"
id: vaultboy id: vaultboy
resize: 168x121 resize: 168x121
type: RGB565 type: RGB565
@@ -108,6 +131,11 @@ external_components:
packages: packages:
common: !include common/common.yaml 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_wo_debug.yaml
# common: !include common/common_dev.yaml # common: !include common/common_dev.yaml
@@ -211,12 +239,32 @@ output:
- platform: ledc - platform: ledc
pin: 16 pin: 16
id: gpio_tft_backlight 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: light:
- platform: monochromatic - platform: monochromatic
id: display_tft_backlight id: display_tft_backlight
output: gpio_tft_backlight output: gpio_tft_backlight
restore_mode: ALWAYS_ON 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: switch:
- platform: template - platform: template
@@ -372,6 +420,7 @@ display:
- platform: mipi_spi - platform: mipi_spi
model: ST7789V model: ST7789V
id: display_tft id: display_tft
byte_order: little_endian # colours were byte-swapped (purple showed as green)
dimensions: dimensions:
height: 128 height: 128
width: 128 width: 128
@@ -384,11 +433,18 @@ display:
# eightbitcolor: true # eightbitcolor: true
update_interval: 1s update_interval: 1s
lambda: |- 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. //Ingress shown animation Frame.
id(blinky).next_frame(); id(blinky).next_frame();
// Draw the animation my_animation at position [x=0,y=0] // Draw the animation my_animation at position [x=0,y=0]
it.image(0, 0, id(blinky), COLOR_ON, COLOR_OFF); it.image(0, 0, id(blinky), COLOR_ON, COLOR_OFF);
// // it.print(0, 0, id(font_default), "Hello World!"); // // 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.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)); // it.rectangle(0, 0, it.get_width(), it.get_height(), id(my_blue));
@@ -491,8 +547,7 @@ sensor:
# name: Dallas Temp 4 # name: Dallas Temp 4
# one_wire_id: hub_1 # one_wire_id: hub_1
time: # time:
- !include common/time/homeassistant.yaml
# - platform: sntp # - platform: sntp
# id: sntp_time # id: sntp_time
# timezone: Europe/Bratislava # timezone: Europe/Bratislava
+9 -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: substitutions:
device: basement-2 device: basement-2
name_short: Basement name_short: Basement
@@ -14,18 +22,11 @@ esphome:
esp8266: esp8266:
board: esp01_1m board: esp01_1m
toolchain: arduino
packages: packages:
common: !include common/common_esp8266.yaml 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: status_led:
pin: pin:
number: 13 number: 13
+10 -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: substitutions:
device: basement device: basement
name: Basement name: Basement
@@ -13,19 +21,11 @@ esphome:
esp8266: esp8266:
board: esp01_1m board: esp01_1m
toolchain: arduino
packages: packages:
common: !include common/common_esp8266.yaml 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: globals:
- id: aerator_auto - id: aerator_auto
type: bool type: bool
@@ -139,8 +139,7 @@ switch:
id: relay_2 id: relay_2
time: time:
- platform: homeassistant - id: !extend ha_time
timezone: Europe/Bratislava
on_time: on_time:
- seconds: 0 - seconds: 0
minutes: /15 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: substitutions:
device: bedroom-lamp-left device: bedroom-lamp-left
name: Bedroom Lamp Left name: Bedroom Lamp Left
@@ -20,26 +39,21 @@ esp32:
sdkconfig_options: sdkconfig_options:
CONFIG_FREERTOS_UNICORE: y CONFIG_FREERTOS_UNICORE: y
advanced: advanced:
flash_chip: generic
ignore_efuse_custom_mac: true ignore_efuse_custom_mac: true
ignore_efuse_mac_crc: true ignore_efuse_mac_crc: true
external_components: external_components:
- source: - source:
type: git type: git
url: https://github.com/mmakaay/esphome-xiaomi_bslamp2 # fork: fix for ESPHome 2026.10 (restore_mode -> restore_state), back to mmakaay once merged
ref: dev url: https://github.com/randybb/esphome-xiaomi_bslamp2
ref: fix-light-restore-state
refresh: 1h refresh: 1h
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.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)
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
# Behavior: default # 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: substitutions:
device: bedroom-lamp-right device: bedroom-lamp-right
name: Bedroom Lamp Right name: Bedroom Lamp Right
@@ -20,26 +39,21 @@ esp32:
sdkconfig_options: sdkconfig_options:
CONFIG_FREERTOS_UNICORE: y CONFIG_FREERTOS_UNICORE: y
advanced: advanced:
flash_chip: generic
ignore_efuse_custom_mac: true ignore_efuse_custom_mac: true
ignore_efuse_mac_crc: true ignore_efuse_mac_crc: true
external_components: external_components:
- source: - source:
type: git type: git
url: https://github.com/mmakaay/esphome-xiaomi_bslamp2 # fork: fix for ESPHome 2026.10 (restore_mode -> restore_state), back to mmakaay once merged
ref: dev url: https://github.com/randybb/esphome-xiaomi_bslamp2
ref: fix-light-restore-state
refresh: 60s refresh: 60s
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.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)
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
# Behavior: default # Behavior: default
+3
View File
@@ -1,4 +1,7 @@
--- ---
# Hardware: Espressif ESP32-C6-DevKitC-1
# Pinout:
# GPIO8 -> LED (light esp32_rmt_led_strip)
substitutions: substitutions:
device: c6-test-1 device: c6-test-1
name: 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: substitutions:
device: c6-test-2 device: c6-test-2
name: 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: substitutions:
device: cam-1 device: cam-1
name: 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: substitutions:
device: can-node-1 device: can-node-1
name: 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: substitutions:
device: can-node-2 device: can-node-2
name: 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: substitutions:
device: cec-bedroom device: cec-bedroom
name: Bedroom TV name: Bedroom TV
@@ -15,6 +24,8 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd # ESP32-PICO-D4, like the other M5Stamp Pico (not read from the device)
type: esp-idf type: esp-idf
external_components: external_components:
@@ -31,11 +42,6 @@ packages:
debug: debug:
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
i2c: i2c:
# - id: i2c0 # - id: i2c0
sda: 32 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: substitutions:
device: clock-1 device: clock-1
name: Clock 1 name: Clock 1
@@ -17,27 +31,15 @@ esp32:
variant: esp32c3 variant: esp32c3
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: generic
type: esp-idf type: esp-idf
# version: 5.4.2 # version: 5.4.2
# platform_version: 54.03.21 # platform_version: 54.03.21
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.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?)
# https://github.com/granadaxronos/120-SONG_NOKIA_RTTTL_RINGTONE_PLAYER_FOR_ARDUINO_UNO/blob/master/RTTTL_PLAYER/songs.h # https://github.com/granadaxronos/120-SONG_NOKIA_RTTTL_RINGTONE_PLAYER_FOR_ARDUINO_UNO/blob/master/RTTTL_PLAYER/songs.h
api: api:
@@ -109,11 +111,6 @@ globals:
restore_value: no restore_value: no
initial_value: "false" initial_value: "false"
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
display: display:
- platform: tm1637 - platform: tm1637
id: tm1637_display 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: substitutions:
device: clock-living-room device: clock-living-room
name: Living room Clock name: Living room Clock
@@ -15,6 +24,8 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd # ESP32-PICO-D4, like the other M5Stamp Pico (not read from the device)
type: esp-idf type: esp-idf
external_components: external_components:
@@ -51,11 +62,6 @@ globals:
restore_value: no restore_value: no
initial_value: "false" initial_value: "false"
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
name: Button name: Button
+235
View File
@@ -0,0 +1,235 @@
---
# Hardware: M5Stack M5Stamp S3 in the ESPendant case (github.com/positron96/ESP32_CNC_Pendant),
# talks to Klipper over Moonraker HTTP API
# Pinout:
# GPIO0 Stamp button (boot) -> stamp_button (binary_sensor gpio) (inverted)
# GPIO1 Handwheel A -> handwheel (sensor rotary_encoder pin_a)
# GPIO2 Handwheel B -> handwheel (sensor rotary_encoder pin_b)
# GPIO4 Axis encoder A -> axis_encoder (sensor rotary_encoder pin_a)
# GPIO5 Axis encoder B -> axis_encoder (sensor rotary_encoder pin_b)
# GPIO6 Axis encoder push -> axis_button (binary_sensor gpio) (inverted)
# GPIO7 Step encoder A -> step_encoder (sensor rotary_encoder pin_a)
# GPIO8 Step encoder B -> step_encoder (sensor rotary_encoder pin_b)
# GPIO9 Step encoder push -> step_button (binary_sensor gpio) (inverted)
# GPIO10 BT1 -> bt1 (binary_sensor gpio) (inverted)
# GPIO11 BT2 -> bt2 (binary_sensor gpio) (inverted)
# GPIO12 BT3 -> bt3 (binary_sensor gpio) (inverted)
# GPIO13 LCD E (SCK) -> spi (spi clk_pin)
# GPIO14 LCD R/W (MOSI) -> spi (spi mosi_pin)
# GPIO15 LCD RS (CS) -> lcd (display st7920 cs_pin)
# GPIO21 RGB LED -> status_rgb (light esp32_rmt_led_strip)
# GPIO39-44 free (BT4-BT6 later)
# LCD RST: RC to 3.3 V, PSB to GND (serial mode)
substitutions:
device: cnc-pendant
name: CNC Pendant
area: Workshop
comment: Klipper CNC pendant
moonraker: http://klipper.local:7125
max_feed: "3000" # mm/min, handwheel jog feed cap
esphome:
name: mcu-${device}
friendly_name: ${name}
area: ${area}
comment: ${comment}
includes:
- include/moonraker.h
on_boot:
- lambda: 'moonraker::client.start("${moonraker}");'
esp32:
variant: esp32s3
flash_size: 8MB
toolchain: esp-idf
framework:
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: status_rgb
light:
- platform: esp32_rmt_led_strip
id: status_rgb
name: LED
pin: 21
num_leds: 1
chipset: ws2812
rgb_order: GRB
restore_mode: ALWAYS_OFF
# only links esp_http_client for include/moonraker.h, which runs requests on its own task
http_request:
globals:
- id: axis
type: int
initial_value: "0" # 0 X, 1 Y, 2 Z
- id: step
type: int
initial_value: "1" # index into steps[] in the jog interval
- id: wheel_sent
type: float
initial_value: "0"
interval:
# handwheel: send the counts since the last jog as one relative move
- interval: 100ms
then:
- lambda: |-
static const float steps[] = {0.01f, 0.1f, 1.0f};
float delta = id(handwheel).state - id(wheel_sent);
if (delta == 0 || std::isnan(delta)) return;
id(wheel_sent) = id(handwheel).state;
float dist = delta * steps[id(step)];
// feed so the move takes ~100 ms, i.e. about one interval
// ponytail: capped feed lets fast spins queue moves that keep running after the wheel stops; drop excess counts if that bites
float feed = std::min(std::max(std::fabs(dist) * 600.0f, 60.0f), ${max_feed}.0f);
moonraker::client.gcode(str_sprintf("G91\nG1 %c%.3f F%.0f\nG90", "XYZ"[id(axis)], dist, feed));
sensor:
- platform: rotary_encoder
id: handwheel
pin_a:
number: 1
mode: INPUT_PULLUP
pin_b:
number: 2
mode: INPUT_PULLUP
resolution: 1 # calibration: counts per detent, flip pin_a/pin_b if direction is wrong
- platform: rotary_encoder
id: axis_encoder
pin_a:
number: 4
mode: INPUT_PULLUP
pin_b:
number: 5
mode: INPUT_PULLUP
on_clockwise:
- lambda: 'id(axis) = std::min(id(axis) + 1, 2);'
on_anticlockwise:
- lambda: 'id(axis) = std::max(id(axis) - 1, 0);'
- platform: rotary_encoder
id: step_encoder
pin_a:
number: 7
mode: INPUT_PULLUP
pin_b:
number: 8
mode: INPUT_PULLUP
on_clockwise:
- lambda: 'id(step) = std::min(id(step) + 1, 2);'
on_anticlockwise:
- lambda: 'id(step) = std::max(id(step) - 1, 0);'
binary_sensor:
- platform: gpio
id: stamp_button
name: Stamp Button
pin:
number: 0
inverted: true
# axis push: zero the selected axis in work coordinates
- platform: gpio
id: axis_button
name: Axis Button
pin:
number: 6
mode: INPUT_PULLUP
inverted: true
filters:
- delayed_on_off: 20ms
on_press:
- lambda: 'moonraker::client.gcode(str_sprintf("G92 %c0", "XYZ"[id(axis)]));'
- platform: gpio
id: step_button
name: Step Button
pin:
number: 9
mode: INPUT_PULLUP
inverted: true
filters:
- delayed_on_off: 20ms
# BT1: home all
- platform: gpio
id: bt1
name: BT1
pin:
number: 10
mode: INPUT_PULLUP
inverted: true
filters:
- delayed_on_off: 20ms
on_press:
- lambda: 'moonraker::client.gcode("G28");'
# BT2: pause / resume
- platform: gpio
id: bt2
name: BT2
pin:
number: 11
mode: INPUT_PULLUP
inverted: true
filters:
- delayed_on_off: 20ms
on_press:
- lambda: 'moonraker::client.post(moonraker::client.status().state == "paused" ? "/printer/print/resume" : "/printer/print/pause");'
# BT3: hold 1 s for emergency stop (Klipper needs FIRMWARE_RESTART afterwards)
- platform: gpio
id: bt3
name: BT3
pin:
number: 12
mode: INPUT_PULLUP
inverted: true
filters:
- delayed_on_off: 20ms
on_multi_click:
- timing:
- ON for at least 1s
then:
- lambda: 'moonraker::client.post("/printer/emergency_stop", "", true);'
font:
# X11 misc-fixed bitmap fonts (as in u8g2 / Marlin), 6 px wide: axis letter + "-123.456" fits 64 px
- file: assets/fonts/6x13.bdf
id: font_big
- file: assets/fonts/6x10.bdf
id: font_small
spi:
clk_pin: 13
mosi_pin: 14
display:
- platform: st7920
id: lcd
cs_pin:
number: 15
inverted: true # ST7920 RS/CS is active high
data_rate: 1MHz # default 200kHz takes ~220 ms per frame; drop back if the picture garbles
width: 128
height: 64
rotation: 90 # mounted portrait, 270 if upside down
update_interval: 200ms
lambda: |-
static const char *steps[] = {"0.01", "0.1", "1"};
auto s = moonraker::client.status();
it.printf(0, 0, id(font_small), "%s", s.state.c_str());
it.printf(0, 10, id(font_small), "H:%s", s.homed.empty() ? "-" : s.homed.c_str());
for (int i = 0; i < 3; i++) {
int y = 22 + i * 14;
Color c = COLOR_ON;
if (i == id(axis)) {
it.filled_rectangle(0, y, 64, 13);
c = COLOR_OFF;
}
it.printf(1, y + 1, id(font_big), c, "%c", "XYZ"[i]);
it.printf(63, y + 1, id(font_big), c, TextAlign::TOP_RIGHT, "%.3f", s.pos[i]);
}
it.printf(0, 118, id(font_small), "%s mm", steps[id(step)]);
+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: substitutions:
device: desk-lamp device: desk-lamp
name: Desk Lamp name: Desk Lamp
@@ -15,18 +22,13 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.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)
binary_sensor: 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: substitutions:
device: dimmer device: dimmer
name: Dimmer name: Dimmer
@@ -30,10 +37,13 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# fan: # fan:
# - platform: speed # - 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: substitutions:
device: echo-1 device: echo-1
name: Echo 1 name: Echo 1
@@ -15,10 +25,17 @@ esphome:
esp32: esp32:
variant: esp32 variant: esp32
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml 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: api:
actions: 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: substitutions:
device: echo device: echo
name: Echo name: Echo
@@ -16,10 +28,17 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml 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: api:
actions: actions:
@@ -71,11 +90,6 @@ light:
red: led_red red: led_red
green: led_green green: led_green
blue: led_blue blue: led_blue
- platform: status_led
id: led_status
pin:
number: 23
allow_other_uses: true
output: output:
- platform: ledc - platform: ledc
@@ -86,9 +100,7 @@ output:
pin: 25 pin: 25
- platform: ledc - platform: ledc
id: led_blue id: led_blue
pin: pin: 23
number: 23
allow_other_uses: true
i2s_audio: i2s_audio:
- id: speaker_bus - id: speaker_bus
@@ -127,16 +139,15 @@ media_player:
- platform: speaker - platform: speaker
id: media_out id: media_out
name: Player name: Player
codec_support_enabled: false
buffer_size: 14000 buffer_size: 14000
media_pipeline: media_pipeline:
speaker: media_spk_resampling_input speaker: media_spk_resampling_input
# format: WAV format: WAV # only the WAV decoder is built (was codec_support_enabled: false)
# num_channels: 1 # num_channels: 1
# sample_rate: 8000 # Lower sample rate # sample_rate: 8000 # Lower sample rate
announcement_pipeline: announcement_pipeline:
speaker: announcement_spk_resampling_input speaker: announcement_spk_resampling_input
# format: WAV format: WAV
# num_channels: 1 # num_channels: 1
# sample_rate: 8000 # Lower sample rate # sample_rate: 8000 # Lower sample rate
on_play: 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: substitutions:
device: eworkbench device: eworkbench
name: Electronics Workbench name: Electronics Workbench
@@ -22,23 +40,6 @@ esp32:
packages: packages:
common: !include common/common.yaml 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: i2c:
- id: i2c_grove - id: i2c_grove
sda: 1 sda: 1
@@ -242,11 +243,6 @@ binary_sensor:
# on_clockwise: # on_clockwise:
# - display_menu.down: # - display_menu.down:
time:
- platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
# display: # display:
# - platform: tm1637 # - platform: tm1637
# id: tm1637_display # id: tm1637_display
+30 -68
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: substitutions:
device: fireplace device: fireplace
name: Heating Fireplace name: Heating Fireplace
@@ -15,76 +33,30 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
external_components:
# - source: github://pr#12717
# components: [ds248x]
# refresh: 1h
- source: github://pr#13534
components: [ds2482, ds2484, ds248x_base]
refresh: 1h
packages: packages:
common: !include common/common.yaml 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: i2c:
# - id: i2c0
# sda: 26
# scl: 32
# scan: true #false
# - id: i2c1
sda: 25 sda: 25
scl: 21 scl: 21
scan: true #false scan: true #false
# ds248x: ds248x:
# # i2c_id: i2c_main id: ds2484_module
# address: 0x18 # should be the default type: ds2482-100
# # sleep_pin: 32 # remove if not needed, if set the ds248x sleeps when no transaction is in progress address: 0x18
# active_pullup: true # adds a active pullup which should improve signal integrity active_pullup: true
# strong_pullup: false # enables a strong pullup used to provide the needed current for temperature reading without vcc connected
# bus_sleep: true # power down the bus when no transaction is in progres
# one_wire:
# id: one_wire_bus
# platform: ds2484
# active_pullup: true
# ds248x:
# id: ds2484_module
# address: 0x18
# one_wire:
# - platform: ds248x
# ds248x_id: ds2484_module
# id: one_wire_bus
one_wire: one_wire:
id: one_wire_bus - platform: ds248x
platform: ds2482 ds248x_id: ds2484_module
active_pullup: true id: one_wire_bus
pca9554: pca9554:
- id: pca9554_module - id: pca9554_module
@@ -131,16 +103,6 @@ sensor:
# index: 0 # index: 0
name: Temperature name: Temperature
id: 'heating_fireplace_temperature' id: 'heating_fireplace_temperature'
# - platform: dht
# pin: 14
# temperature:
# name: "Kitchen Temperature"
# id: 'kitchen_temperature'
# humidity:
# name: "Kitchen Humidity"
# id: 'kitchen_humidity'
# update_interval: 60s
# model: si7021
bluetooth_proxy: bluetooth_proxy:
active: true active: true
+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: substitutions:
device: gate device: gate
name: Gate name: Gate
@@ -15,25 +30,14 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# PINOUTS: M5ATOM status_led: !include common/status_led_atom.yaml
# 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
button: button:
- platform: output - platform: output
+29 -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: substitutions:
device: gateway device: gateway
name: Gateway name: Gateway
@@ -17,6 +44,7 @@ esp32:
framework: framework:
type: esp-idf type: esp-idf
advanced: advanced:
flash_chip: generic
minimum_chip_revision: 3.0 minimum_chip_revision: 3.0
sram1_as_iram: true sram1_as_iram: true
@@ -32,22 +60,7 @@ external_components:
packages: packages:
# common: !include common/common.yaml # common: !include common/common.yaml
common_eth: !include common/common_eth.yaml common_eth: !include common/common_eth.yaml
ipv6_only: !include common/ipv6_only_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: i2c:
sda: 13 sda: 13
+32 -56
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: substitutions:
device: heater device: heater
name: Heater name: Heater
@@ -25,40 +43,14 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
external_components:
# - source: github://pr#12717
# components: [ds248x]
# refresh: 1h
- source: github://pr#13534
components: [ds2482, ds2484, ds248x_base]
refresh: 1h
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# PINOUTS: M5ATOM status_led: !include common/status_led_atom.yaml
# 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
#logger:
# level: VERBOSE
# logs:
# dallas.component: ERROR
# uart.component: ERROR
# i2c.component: VERBOSE
# Heating / Hot water Controller # Heating / Hot water Controller
# temp_1: Solar Collector # temp_1: Solar Collector
@@ -129,9 +121,7 @@ globals:
initial_value: '20.5' initial_value: '20.5'
time: time:
- platform: homeassistant - id: !extend ha_time
id: ha_time
timezone: Europe/Bratislava
on_time: on_time:
- seconds: 0 - seconds: 0
minutes: /1 minutes: /1
@@ -165,36 +155,22 @@ climate:
default_target_temperature_high: 40 °C default_target_temperature_high: 40 °C
i2c: i2c:
# - id: i2c0
# sda: 26
# scl: 32
# scan: true #false
# - id: i2c1
sda: 25 sda: 25
scl: 21 scl: 21
scan: true #false scan: true #false
# one_wire:
# id: one_wire_bus
# # i2c_id: i2c_main
# platform: ds2484
# active_pullup: true
# ds248x: ds248x:
# id: ds2484_module id: ds2482_module
# address: 0x18 type: ds2482-100
# active_pullup: true address: 0x18
active_pullup: true
# one_wire:
# - platform: ds248x
# ds248x_id: ds2484_module
# id: one_wire_bus
one_wire: one_wire:
id: one_wire_bus - platform: ds248x
# i2c_id: i2c_main ds248x_id: ds2482_module
platform: ds2482 id: one_wire_bus
active_pullup: true
modbus: modbus:
uart_id: uart_modbus uart_id: uart_modbus
+23 -22
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: substitutions:
device: kitchen device: kitchen
name: Kitchen name: Kitchen
@@ -32,33 +49,17 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
api: # api:
reboot_timeout: 300s # 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: i2c:
# - id: i2c0 # - id: i2c0
+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: substitutions:
device: lightening device: lightening
name: Lightening detector name: Lightening detector
@@ -16,6 +26,8 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd # ESP32-PICO-D4, like the other M5Stamp Pico (not read from the device)
type: esp-idf type: esp-idf
packages: 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: substitutions:
device: lvgl-eworkbench device: lvgl-eworkbench
name: Electronics Workbench Display name: Electronics Workbench Display
@@ -16,6 +29,8 @@ esp32:
flash_size: 16MB flash_size: 16MB
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: generic # same board as lvgl-trainer (not read from the device)
type: esp-idf type: esp-idf
packages: 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: substitutions:
device: lvgl-trainer device: lvgl-trainer
name: Trainer Display name: Trainer Display
area: Basement area: Basement
comment: "${area} | Pain Cave" 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: esphome:
name: mcu-${device} name: mcu-${device}
@@ -15,11 +37,13 @@ esp32:
variant: esp32s3 variant: esp32s3
flash_size: 16MB flash_size: 16MB
framework: framework:
advanced:
flash_chip: generic
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
i2c: i2c:
- id: touchscreen_bus - id: touchscreen_bus
@@ -36,71 +60,17 @@ spi:
clk_pin: 47 clk_pin: 47
data_pins: [21, 48, 40, 39] 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: globals:
- id: bgcolor # stopwatch: accumulated time of finished runs + start of the current run
type: Color - id: sw_running
initial_value: "Color::random_color()" type: bool
initial_value: 'false'
# power_supply: - id: sw_start
# id: main_backlight type: uint32_t
# pin: 1 initial_value: '0'
# enable_on_boot: true - id: sw_accum
type: uint32_t
initial_value: '0'
output: output:
- platform: ledc - platform: ledc
@@ -119,7 +89,6 @@ display:
- platform: mipi_spi - platform: mipi_spi
model: AXS15231 model: AXS15231
data_rate: 40MHz #20mhz is default data_rate: 40MHz #20mhz is default
#spi_mode: MODE2
id: main_display id: main_display
spi_id: display_qspi spi_id: display_qspi
dimensions: dimensions:
@@ -127,11 +96,6 @@ display:
width: 320 width: 320
cs_pin: 45 cs_pin: 45
auto_clear_enabled: false 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: touchscreen:
- platform: axs15231 - platform: axs15231
@@ -142,27 +106,8 @@ touchscreen:
# interrupt_pin: # interrupt_pin:
# number: 3 # number: 3
# ignore_strapping_warning: true # ignore_strapping_warning: true
calibration: # no calibration/transform: the driver defaults to the native 320x480 panel and
x_min: 0 # LVGL applies its own rotation to touch points
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
# );
on_release: on_release:
- if: - if:
condition: lvgl.is_paused condition: lvgl.is_paused
@@ -183,107 +128,640 @@ uart:
binary_sensor: binary_sensor:
- platform: homeassistant - platform: homeassistant
id: exercise_room_light id: basement_light
entity_id: light.exercise_room entity_id: ${light_basement}
trigger_on_initial_state: true trigger_on_initial_state: true
on_state: on_state:
then: - lvgl.widget.update:
lvgl.widget.update: id: basement_light_btn
id: exercise_room_light_btn
state: state:
checked: !lambda return x; checked: !lambda return x;
- platform: homeassistant - platform: homeassistant
id: exercise_room_fan id: workbench_light
entity_id: light.mcu_dimmer_exercise_room_fan entity_id: ${light_workbench}
trigger_on_initial_state: true trigger_on_initial_state: true
on_state: on_state:
then: - lvgl.widget.update:
lvgl.widget.update: id: workbench_light_btn
id: exercise_room_fan_btn
state: state:
checked: !lambda return x; 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: lvgl:
rotation: 90 rotation: 90
buffer_size: 100% buffer_size: 100%
log_level: WARN log_level: WARN
color_depth: 16 color_depth: 16
default_font: montserrat_18 default_font: font_ui
# on_idle: bg_color: 0x000000
# - timeout: !lambda "return (id(display_timeout).state * 1000);" text_color: 0xFFFFFF
# then: theme:
# - logger.log: "LVGL is idle" button:
# - light.turn_off: bg_color: 0x2B2F36
# id: display_backlight radius: 12
# transition_length: 2500ms checked:
# - lvgl.pause: 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: top_layer:
widgets: widgets:
- buttonmatrix: - buttonmatrix:
id: nav_bar
align: bottom_mid align: bottom_mid
# styles: header_footer width: 100%
pad_all: 0 height: 56
outline_width: 0 pad_all: 4
id: top_layer pad_column: 6
# items: items:
# styles: header_footer text_font: montserrat_28
rows: rows:
- buttons: - buttons:
- id: page_prev - id: page_prev
text: "\uF053" text: ""
on_press: on_press:
then: then:
lvgl.page.previous: lvgl.page.previous:
- id: page_home - id: page_home
text: "\uF015" text: ""
on_press: on_press:
then: then:
lvgl.page.show: main_page lvgl.page.show: clock_page
- id: page_next - id: page_next
text: "\uF054" text: ""
on_press: on_press:
then: then:
lvgl.page.next: lvgl.page.next:
pages: pages:
- id: main_page # 1: clock (default after boot)
- id: clock_page
widgets: widgets:
- label: - label:
text: "ESPHome LVGL Display" id: clock_label
align: CENTER align: CENTER
text_align: CENTER y: -28
text_color: 0xFFFFFF text_font: font_digits
- id: excercise_page text: "--:--:--"
# 2: basement lights
- id: lights_page
pad_all: 10
widgets: widgets:
- label:
align: CENTER
text: 'Hello World!'
- button: - button:
id: exercise_room_light_btn id: basement_light_btn
align: TOP_LEFT align: TOP_LEFT
width: 100 width: 148
height: 70 height: 80
checkable: true checkable: true
widgets: widgets:
- label: - label:
align: CENTER align: CENTER
text: 'Light' text: "Pivnica"
on_click: on_click:
- homeassistant.action: - homeassistant.action:
action: light.toggle action: light.toggle
data: data:
entity_id: light.exercise_room entity_id: ${light_basement}
- button: - button:
id: exercise_room_fan_btn id: workbench_light_btn
align: TOP_RIGHT align: TOP_MID
width: 100 width: 148
height: 70 height: 80
checkable: true checkable: true
widgets: widgets:
- label: - label:
align: CENTER align: CENTER
text: 'Fan' text: "Pracovný stôl"
on_click: on_click:
- homeassistant.action: - homeassistant.action:
action: light.toggle action: light.toggle
data: data:
entity_id: light.mcu_dimmer_exercise_room_fan 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: substitutions:
device: lvgl device: lvgl
name: LVGL name: LVGL
@@ -10,18 +94,22 @@ esphome:
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} comment: ${comment}
platformio_options: on_boot:
board_build.flash_mode: dio - priority: -100
then:
- lvgl.page.show: status_page
esp32: esp32:
variant: esp32s3 variant: esp32s3
flash_size: 16MB flash_size: 16MB
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf 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: sdkconfig_options:
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: y
CONFIG_ESP32S3_DATA_CACHE_64KB: y CONFIG_ESP32S3_DATA_CACHE_64KB: y
CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y CONFIG_SPIRAM_FETCH_INSTRUCTIONS: y
CONFIG_SPIRAM_RODATA: y CONFIG_SPIRAM_RODATA: y
@@ -32,62 +120,26 @@ psram:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# PINOUTS: ESP32 Cheap Yellow Display, 4.3", IPS, Capacitive api:
## Display # status page until Home Assistant connects (log viewers don't subscribe to states)
# R0 GND on_client_connected:
# R1 GND - delay: 2s
# R2 GND - if:
# R3 45 condition:
# R4 48 api.connected:
# R5 47 state_subscription_only: true
# R6 21 then:
# R7 14 - lvgl.page.show: main_page
# G0 GND on_client_disconnected:
# G1 GND - if:
# G2 5 condition:
# G3 6 not:
# G4 7 api.connected:
# G5 15 state_subscription_only: true
# G6 16 then:
# G7 4 - lvgl.page.show: status_page
# 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
i2c: i2c:
- id: i2c_main - id: i2c_main
@@ -95,573 +147,223 @@ i2c:
scl: 20 scl: 20
scan: true scan: true
# same pins and timing as the 5" Sunton board, pclk lowered for the 4.3" panel
display: display:
- platform: rpi_dpi_rgb - platform: mipi_rgb
model: ESP32-8048S050
id: main_display id: main_display
color_order: RGB color_order: RGB
invert_colors: true invert_colors: true
pclk_frequency: 12.5MHz
update_interval: never update_interval: never
auto_clear_enabled: false # takes 2.8 seconds to clear the display 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: output:
- platform: ledc - platform: ledc
id: gpio_backlight_pwm
pin: 2 pin: 2
frequency: 1220 frequency: 1220
id: gpio_backlight_pwm
light: light:
- platform: monochromatic - platform: monochromatic
output: gpio_backlight_pwm
id: back_light id: back_light
name: Backlight
output: gpio_backlight_pwm
restore_mode: ALWAYS_ON 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: 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: then:
# - lvgl.indicator.line.update:
# id: power_meter_input
# value: !lambda return id(counting_number).state;
- lvgl.label.update: - lvgl.label.update:
id: battery_kw id: clock_label
text: !lambda |- text: !lambda |-
static char buf[8]; auto now = id(ha_time).now();
snprintf(buf, sizeof(buf), "%.1fkW", id(counting_number).state); if (!now.is_valid())
return buf; return std::string("--:--");
- lvgl.label.update: return now.strftime("%H:%M");
id: battery_status - if:
text_color: 0xFF0000 condition:
#text: "charging" lvgl.page.is_showing: status_page
text: "discharging" then:
- lvgl.label.update: - script.execute: update_status
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
image: image:
- file: mdi:sun-wireless-outline - platform: file
#"solar-power-invert.png" file: assets/images/made-for-esphome-white-on-black.svg
# mdi:solar-power id: esphome_logo
# mdi:battery-charging-outline resize: 400x118
# mdi:battery-arrow-up-outline type: RGB565
# mdi:battery-arrow-down-outline transparency: alpha_channel
id: solar_power_icon
resize: 50x50
type: BINARY
- file: mdi:battery-arrow-down-outline font:
id: home_battery_icon - file: "gfonts://Roboto@500"
resize: 30x30 id: font_clock
type: BINARY 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: lvgl:
log_level: INFO log_level: WARN
color_depth: 16 color_depth: 16
#buffer_size: 25% bg_color: 0x000000
bg_color: 0 text_color: 0xFFFFFF
border_width: 0 theme:
outline_width: 0 buttonmatrix:
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_opa: TRANSP bg_opa: TRANSP
bg_color: 0 border_width: 0
radius: 4 items:
pad_all: 2 bg_color: 0x2B2F36
- id: details_style text_color: 0xFFFFFF
text_font: MONTSERRAT_18 radius: 12
align: center checked:
text_color: 0xFFFFFF bg_color: 0xE08A00
#bg_opa: cover top_layer:
bg_opa: TRANSP widgets:
bg_color: 0 # same navigation bar as on mcu-lvgl-trainer
radius: 4 - buttonmatrix:
pad_all: 2 id: nav_bar
widgets: align: bottom_mid
- obj: # Meter width: 100%
height: 240 height: 64
width: 240 pad_all: 4
#bg_opa: TRANSP pad_column: 6
bg_color: 0 items:
border_width: 0 text_font: montserrat_28
outline_width: 0 rows:
shadow_width: 0 - buttons:
pad_all: 4 - id: page_prev
align: TOP_LEFT text: "\uF053"
#scrollbar_mode: "off" on_press:
widgets: then:
- meter: # Gradient color arc lvgl.page.previous:
height: 100% - id: page_home
width: 100% text: "\uF015"
border_width: 0 on_press:
outline_width: 0 then:
align: center lvgl.page.show: main_page
bg_color: 0 - id: page_next
styles: meter_style text: "\uF054"
#bg_opa: TRANSP on_press:
scales: then:
angle_range: 180 # sets the total angle to 180 = starts mid left and ends mid right lvgl.page.next:
range_to: 10 pages:
range_from: -10 # 1: clock
ticks: - id: main_page
count: 0 widgets:
indicators: - label:
- line: id: clock_label
id: power_meter_input align: CENTER
width: 8 y: -32
color: 0xFFFFFF text_font: font_clock
r_mod: 12 #sets line length by this much difference from the scale default radius text: "--:--"
value: 50
# - image: # 2: status (shown until Home Assistant connects)
# id: power_meter_input_img - id: status_page
- arc: on_load:
color: 0xFF3000 - script.execute: update_status
r_mod: 10 #radius difference from the scale default radius widgets:
width: 20 - image:
start_value: -10 src: esphome_logo
end_value: 0 align: TOP_MID
- arc: y: 16
color: 0x00FF00 - label:
r_mod: 10 #radius difference from the scale default radius align: TOP_MID
width: 20 y: 140
start_value: 0 text_font: font_title
end_value: 10 text: "${name}"
#- canvas: - obj:
- arc: # black arc to erase middle part of meter indicator line id: status_lines
height: 160 x: 60
width: 160 y: 196
align: center width: 700
arc_color: 0x000000 # background color height: SIZE_CONTENT
arc_width: 150 bg_opa: TRANSP
start_angle: 0 border_width: 0
end_angle: 360 pad_all: 0
indicator: scrollbar_mode: "OFF"
arc_width: 150 layout:
arc_color: 0x000000 type: flex
- label: # gauge lower and higher range indicators flex_flow: column
styles: font_style pad_row: 8
text_font: MONTSERRAT_18 # override font size widgets:
y: 8 #negative = higher - label:
x: -99 id: status_wifi
text: "-10" text_font: font_status
- label: text: ""
styles: font_style - label:
text_font: MONTSERRAT_18 # override font size id: status_ips
y: 8 #negative = higher text_font: font_status
x: 99 text_color: 0x8C8C8C
text: "+10" pad_left: 30
- label: text: ""
styles: font_style - label:
id: battery_status id: status_ha
y: -35 #negative = higher text_font: font_status
- label: text: ""
styles: font_style - label:
id: battery_kw id: status_footer
y: -60 text_font: font_status
- label: text_color: 0x8C8C8C
styles: font_style text: ""
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
+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: substitutions:
device: m5paper device: m5paper
name: M5Paper name: M5Paper
area: DEV area: DEV
comment: M5Paper 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: esphome:
name: mcu-${device} name: mcu-${device}
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} 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: esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
type: esp-idf type: esp-idf
advanced:
flash_chip: generic
minimum_chip_revision: 3.0
sram1_as_iram: true
psram: psram:
external_components:
- source: github://Passific/m5paper_esphome
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
time: globals:
- platform: homeassistant - id: show_status
id: ha_time type: bool
timezone: Europe/Bratislava initial_value: 'true'
on_time_sync: - id: usb_mode
- bm8563.write_time type: bool
- platform: bm8563 initial_value: 'false'
id: rtc_time - id: rtc_wake
sleep_duration: 3600000ms 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: wifi:
battery_power_pin: GPIO5 enable_on_boot: false
main_power_pin: GPIO2 on_connect:
# update_interval: 10s - if:
# battery_voltage: condition:
# name: "${name} Battery" 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 # 0x44 SHT30
# 0x50 # 0x50 FM24C02 EEPROM (unused)
# 0x51 # 0x51 BM8563 RTC
# 0x5D GT911 # 0x5D GT911 touch (docs say 0x14; the driver tries 0x5D, then 0x14)
i2c: i2c:
- id: i2c_main - id: i2c_main
sda: 21 sda: 21
scl: 22 scl: 22
scan: true #false scan: true
# Port A
# - id: i2c_a # - id: i2c_a
# sda: 25 # sda: 25
# scl: 32 # scl: 32
# scan: true #false # Port B
# - id: i2c_b # - id: i2c_b
# sda: 26 # sda: 26
# scl: 33 # scl: 33
# scan: true #false # Port C
# - id: i2c_c # - id: i2c_c
# sda: 18 # sda: 18
# scl: 19 # scl: 19
# scan: true #false
spi: spi:
clk_pin: 14 clk_pin: 14
miso_pin: 13 miso_pin: 13
mosi_pin: 12 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: binary_sensor:
- platform: gpio - platform: gpio
name: ${name} Button UP name: ${name} Button UP
id: button_up id: button_up
pin: pin:
number: 37 number: GPIO37
inverted: true inverted: true
on_press: on_press:
- component.update: m5paper_display - component.update: m5paper_display
on_release:
- component.update: m5paper_display
- platform: gpio - platform: gpio
name: ${name} Button Press name: ${name} Button Press
id: button_press id: button_press
pin: pin:
number: 38 number: GPIO38
inverted: true inverted: true
- platform: gpio - platform: gpio
name: ${name} Button Down name: ${name} Button Down
id: button_down id: button_down
pin: pin:
number: 39 number: GPIO39
inverted: true inverted: true
- platform: touchscreen - platform: touchscreen
name: ${name} Top Left Touch Button name: ${name} Top Left Touch Button
@@ -103,51 +410,19 @@ binary_sensor:
y_min: 0 y_min: 0
y_max: 100 y_max: 100
on_press: on_press:
# Example of applying the sleep duration and shutting down to the lowest power mode - script.execute: battery_cycle
- bm8563.apply_sleep_duration
- delay: 1s
- m5paper.shutdown_main_power
font: button:
- file: "gfonts://Roboto" - platform: template
id: font_default name: Refresh Display
size: 20 entity_category: config
- file: "gfonts://Roboto" on_press:
id: roboto_32 - component.update: m5paper_display
size: 32 - platform: template
- file: "gfonts://Roboto" name: Refresh Calendar
id: roboto_24 entity_category: config
size: 24 on_press:
- file: "gfonts://Roboto" - script.execute: fetch_events
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!");
sensor: sensor:
- platform: sht3xd - platform: sht3xd
@@ -156,9 +431,257 @@ sensor:
id: current_temperature id: current_temperature
humidity: humidity:
name: Humidity name: Humidity
id: current_humidity
address: 0x44 address: 0x44
update_interval: 60s 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: .image_defaults:
# - platform: gt911 icon: &icon {platform: file, type: BINARY, transparency: chroma_key}
# interrupt_pin: 36
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: substitutions:
device: mains-power device: mains-power
name: Mains Power name: Mains Power
@@ -22,25 +37,14 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# PINOUTS: M5ATOM status_led: !include common/status_led_atom.yaml
# 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
modbus: modbus:
uart_id: uart_modbus uart_id: uart_modbus
@@ -228,9 +232,7 @@ button:
- pzemac.reset_energy: pzemac_l3 - pzemac.reset_energy: pzemac_l3
time: time:
- platform: homeassistant - id: !extend ha_time
id: ha_time
timezone: Europe/Bratislava
on_time: on_time:
- cron: '0 0 0 * * *' - cron: '0 0 0 * * *'
then: then:
+185
View File
@@ -0,0 +1,185 @@
---
# Hardware: Nordic nRF52840 DK
# Pinout:
# P0.06 UART0 TX -> logger (J-Link VCOM)
# P0.13 LED 1 (active low) -> ANT+ Connected (a configured device is received)
# P0.14 LED 2 (active low) -> ANT+ Unknown Device (an unconfigured one is in range)
# P1.01 UART1 RX <- mcu-nrf-dk UART1 TX (P1.02), packet_transport
# P1.02 UART1 TX -> mcu-nrf-dk UART1 RX (P1.01), packet_transport; plus GND
# Radio: ANT+ receiver (RadiANT), no network of its own; values go to mcu-nrf-dk
# ANT+ devices:
# 655730 Garmin HRM-Pro heart rate
# 498521 Concept2 PM5 (rower) fitness equipment (FE-C)
# 1044953 Garmin Tempe environment (temperature)
# 604693 Garmin Varia RTL515 bike radar, battery only
# 136052 Garmin HRM-Dual heart rate (pain cave)
# 334424 Garmin HRM-Tri heart rate (bike)
# 886796 Garmin Rally RS200 power + cadence
# 343922 Garmin Speed Sensor 2 speed
# 42898 SRAM Force AXS shifting (Cube Litening C:68X), battery only
esphome:
name: mcu-nrf-ant
friendly_name: nRF ANT+
# needs the esphomeplatformzephyr fork (esphome-zephyr); RadiANT needs NCS
zephyr:
variant: NRF52
board: nrf52840dk/nrf52840
framework:
type: ncs
logger:
hardware_uart: UART0
external_components:
- source: github://randybb/esphome-components
components: [ant_plus]
output:
- platform: gpio
id: led_known
pin: {number: P0.13, inverted: true}
- platform: gpio
id: led_unknown
pin: {number: P0.14, inverted: true}
ant_plus:
network_key: !secret ant_plus_network_key
connected:
id: ant_connected
name: ANT+ Connected
on_press: {output.turn_on: led_known}
on_release: {output.turn_off: led_known}
unknown_device:
id: ant_unknown_device
name: ANT+ Unknown Device
on_press: {output.turn_on: led_unknown}
on_release: {output.turn_off: led_unknown}
devices:
- type: heart_rate # Garmin HRM-Pro
device_number: 655730
heart_rate:
id: hrm_pro_heart_rate
name: Garmin HRM-Pro Heart Rate
battery_level:
id: hrm_pro_battery
name: Garmin HRM-Pro Battery
- type: fitness_equipment # Concept2 PM5 (rower)
device_number: 498521
power:
id: pm5_power
name: Concept2 PM5 Power
cadence:
id: pm5_stroke_rate
name: Concept2 PM5 Stroke Rate
in_use:
id: pm5_in_use
name: Concept2 PM5 In Use
- type: temperature # Garmin Tempe
device_number: 1044953
temperature:
id: tempe_temperature
name: Garmin Tempe Temperature
temperature_min:
id: tempe_temperature_min
name: Garmin Tempe Temperature 24h Min
temperature_max:
id: tempe_temperature_max
name: Garmin Tempe Temperature 24h Max
battery_voltage:
id: tempe_battery
name: Garmin Tempe Battery
battery_low:
id: tempe_battery_low
name: Garmin Tempe Battery Low
- type: bike_radar # Garmin Varia RTL515
device_number: 604693
battery_voltage:
id: varia_battery
name: Garmin Varia RTL515 Battery
battery_low:
id: varia_battery_low
name: Garmin Varia RTL515 Battery Low
- type: heart_rate # Garmin HRM-Dual
device_number: 136052
heart_rate:
id: hrm_dual_heart_rate
name: Garmin HRM-Dual Heart Rate
battery_level:
id: hrm_dual_battery
name: Garmin HRM-Dual Battery
- type: heart_rate # Garmin HRM-Tri
device_number: 334424
heart_rate:
id: hrm_tri_heart_rate
name: Garmin HRM-Tri Heart Rate
battery_level:
id: hrm_tri_battery
name: Garmin HRM-Tri Battery
- type: power # Garmin Rally RS200 (a battery in each pedal)
device_number: 886796
power:
id: rally_power
name: Garmin Rally RS200 Power
cadence:
id: rally_cadence
name: Garmin Rally RS200 Cadence
battery_low:
id: rally_battery_low
name: Garmin Rally RS200 Battery Low
- type: speed # Garmin Speed Sensor 2
device_number: 343922
speed:
id: speed2_speed
name: Garmin Speed Sensor 2 Speed
battery_voltage:
id: speed2_battery
name: Garmin Speed Sensor 2 Battery
battery_low:
id: speed2_battery_low
name: Garmin Speed Sensor 2 Battery Low
- type: shifting # SRAM Force AXS (Cube Litening C:68X)
device_number: 42898
battery_low:
id: sram_battery_low
name: SRAM Force AXS Battery Low
uart:
id: link
port: UART1
# the DK's default UART1 pins, same on both boards, wires crossed
tx_pin: P1.02
rx_pin: P1.01
baud_rate: 115200
packet_transport:
- platform: uart
uart_id: link
update_interval: 1s
sensors:
- hrm_pro_heart_rate
- hrm_pro_battery
- pm5_power
- pm5_stroke_rate
- tempe_temperature
- tempe_temperature_min
- tempe_temperature_max
- tempe_battery
- varia_battery
- hrm_dual_heart_rate
- hrm_dual_battery
- hrm_tri_heart_rate
- hrm_tri_battery
- rally_power
- rally_cadence
- speed2_speed
- speed2_battery
binary_sensors:
- ant_connected
- ant_unknown_device
- pm5_in_use
- tempe_battery_low
- varia_battery_low
- rally_battery_low
- speed2_battery_low
- sram_battery_low
+290 -5
View File
@@ -1,11 +1,296 @@
--- ---
# Hardware: Nordic nRF52840 DK
# Pinout:
# P0.11 Button 1 (active low) -> Button 1 (binary_sensor gpio)
# P0.12 Button 2 (active low) -> Button 2 (binary_sensor gpio)
# P0.13 LED 1 (active low) -> LED 1 (light binary)
# P0.14 LED 2 (active low) -> LED 2 (light binary)
# P0.15 LED 3 (active low) -> LED 3 (light binary)
# P0.16 LED 4 (active low) -> LED 4 (light binary)
# P0.24 Button 3 (active low) -> Button 3 (binary_sensor gpio)
# P0.25 Button 4 (active low) -> Button 4 (binary_sensor gpio)
# P1.01 UART1 RX <- mcu-nrf-ant UART1 TX (P1.02), packet_transport; plus GND
# P1.02 UART1 TX -> mcu-nrf-ant UART1 RX (P1.01), packet_transport
# ANT+ values (Garmin HRM-Pro, Concept2 PM5, Garmin Tempe, Garmin Varia RTL515) come from mcu-nrf-ant
esphome: esphome:
name: mcu-nrf-dk name: mcu-nrf-dk
friendly_name: mcu-nrf-dk friendly_name: nRF DK
nrf52: # needs the esphomeplatformzephyr fork (esphome-zephyr), upstream has no zephyr: platform yet
board: nrf52840_dk zephyr:
bootloader: adafruit_nrf52_sd140_v7 variant: NRF52
board: nrf52840dk/nrf52840
framework:
type: zephyr
# Enable logging
logger: logger:
network:
enable_ipv6: true
# Active dataset of the Thread network (HA: Settings > Thread > ... > dataset TLV)
openthread:
tlv: !secret thread_tlv
# end device, doesn't route for others; saves flash (FTD fills the MCUboot slot)
device_type: MTD
api:
encryption:
key: !secret api_key
# ANT+ values from mcu-nrf-ant (second nRF52840 DK) over UART
uart:
id: ant_link
port: UART1
# the DK's default UART1 pins, same on both boards, wires crossed
rx_pin: P1.01
tx_pin: P1.02
baud_rate: 115200
packet_transport:
- platform: uart
uart_id: ant_link
providers:
- name: mcu-nrf-ant
sensor:
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: hrm_pro_heart_rate
name: Garmin HRM-Pro Heart Rate
internal: false
unit_of_measurement: bpm
icon: mdi:heart-pulse
filters:
- throttle: 1s
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: hrm_pro_battery
name: Garmin HRM-Pro Battery
internal: false
unit_of_measurement: "%"
device_class: battery
entity_category: diagnostic
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: pm5_power
name: Concept2 PM5 Power
internal: false
unit_of_measurement: W
device_class: power
filters:
- throttle: 1s
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: pm5_stroke_rate
name: Concept2 PM5 Stroke Rate
internal: false
unit_of_measurement: spm
icon: mdi:rowing
filters:
- throttle: 1s
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: tempe_temperature
name: Garmin Tempe Temperature
internal: false
unit_of_measurement: °C
device_class: temperature
accuracy_decimals: 1
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: tempe_temperature_min
name: Garmin Tempe Temperature 24h Min
internal: false
unit_of_measurement: °C
device_class: temperature
accuracy_decimals: 1
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: tempe_temperature_max
name: Garmin Tempe Temperature 24h Max
internal: false
unit_of_measurement: °C
device_class: temperature
accuracy_decimals: 1
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: tempe_battery
name: Garmin Tempe Battery
internal: false
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 2
entity_category: diagnostic
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: varia_battery
name: Garmin Varia RTL515 Battery
internal: false
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 2
entity_category: diagnostic
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: hrm_dual_heart_rate
name: Garmin HRM-Dual Heart Rate
internal: false
unit_of_measurement: bpm
icon: mdi:heart-pulse
filters:
- throttle: 1s
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: hrm_dual_battery
name: Garmin HRM-Dual Battery
internal: false
unit_of_measurement: "%"
device_class: battery
entity_category: diagnostic
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: hrm_tri_heart_rate
name: Garmin HRM-Tri Heart Rate
internal: false
unit_of_measurement: bpm
icon: mdi:heart-pulse
filters:
- throttle: 1s
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: hrm_tri_battery
name: Garmin HRM-Tri Battery
internal: false
unit_of_measurement: "%"
device_class: battery
entity_category: diagnostic
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: rally_power
name: Garmin Rally RS200 Power
internal: false
unit_of_measurement: W
device_class: power
filters:
- throttle: 1s
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: rally_cadence
name: Garmin Rally RS200 Cadence
internal: false
unit_of_measurement: rpm
icon: mdi:rotate-right
filters:
- throttle: 1s
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: speed2_speed
name: Garmin Speed Sensor 2 Speed
internal: false
unit_of_measurement: m/s
device_class: speed
accuracy_decimals: 2
filters:
- throttle: 1s
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: speed2_battery
name: Garmin Speed Sensor 2 Battery
internal: false
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 2
entity_category: diagnostic
output:
- platform: gpio
id: led_1_out
pin: {number: P0.13, inverted: true}
- platform: gpio
id: led_2_out
pin: {number: P0.14, inverted: true}
- platform: gpio
id: led_3_out
pin: {number: P0.15, inverted: true}
- platform: gpio
id: led_4_out
pin: {number: P0.16, inverted: true}
light:
- {platform: binary, name: LED 1, id: led_1, output: led_1_out}
- {platform: binary, name: LED 2, id: led_2, output: led_2_out}
- {platform: binary, name: LED 3, id: led_3, output: led_3_out}
- {platform: binary, name: LED 4, id: led_4, output: led_4_out}
# each button toggles its LED locally and is visible in HA
binary_sensor:
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: ant_connected
name: ANT+ Connected
internal: false
device_class: connectivity
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: ant_unknown_device
name: ANT+ Unknown Device
internal: false
icon: mdi:access-point
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: pm5_in_use
name: Concept2 PM5 In Use
internal: false
device_class: running
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: tempe_battery_low
name: Garmin Tempe Battery Low
internal: false
device_class: battery
entity_category: diagnostic
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: varia_battery_low
name: Garmin Varia RTL515 Battery Low
internal: false
device_class: battery
entity_category: diagnostic
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: rally_battery_low
name: Garmin Rally RS200 Battery Low
internal: false
device_class: battery
entity_category: diagnostic
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: speed2_battery_low
name: Garmin Speed Sensor 2 Battery Low
internal: false
device_class: battery
entity_category: diagnostic
- platform: packet_transport
provider: mcu-nrf-ant
remote_id: sram_battery_low
name: SRAM Force AXS Battery Low
internal: false
device_class: battery
entity_category: diagnostic
- platform: gpio
name: Button 1
pin: {number: P0.11, inverted: true, mode: {input: true, pullup: true}}
on_press: {light.toggle: led_1}
- platform: gpio
name: Button 2
pin: {number: P0.12, inverted: true, mode: {input: true, pullup: true}}
on_press: {light.toggle: led_2}
- platform: gpio
name: Button 3
pin: {number: P0.24, inverted: true, mode: {input: true, pullup: true}}
on_press: {light.toggle: led_3}
- platform: gpio
name: Button 4
pin: {number: P0.25, inverted: true, mode: {input: true, pullup: true}}
on_press: {light.toggle: led_4}
+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: substitutions:
device: nspanel-bedroom device: nspanel-bedroom
name: Bedroom NSPanel name: Bedroom NSPanel
@@ -11,103 +25,20 @@ esphome:
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} 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: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
script: nspanel: !include
- id: apply_sleep_dim file: common/nspanel.yaml
then: vars:
- lambda: |- temperature_entity: sensor.zigbee_bedroom_temperature
uint8_t dim; sleep_dim: !include
if (id(bedroom_lights).state) dim = 5; // sleepOverride file: common/nspanel_sleep_dim.yaml
else if (id(sun_id).is_above_horizon(-6)) dim = 5; // day vars:
else dim = 0; // night sleep_override_entity: light.bedroom_lights
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
nspanel_lovelace: 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: cards:
- type: cardGrid - type: cardGrid
title: Spálňa title: Spálňa
@@ -135,12 +66,12 @@ nspanel_lovelace:
title: Kúrenie title: Kúrenie
thermo_entity_id: climate.bt_trv_bedroom thermo_entity_id: climate.bt_trv_bedroom
time: - type: cardEntities
- platform: homeassistant title: Info
id: ha_time entities:
timezone: Europe/Bratislava - name: Zariadenie
on_time_sync: entity_id: button.bedroom_nspanel_info
- script.execute: apply_sleep_dim icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
@@ -166,12 +97,6 @@ binary_sensor:
entity_id: light.bedroom_lamps entity_id: light.bedroom_lamps
- lambda: 'id(nspanel_id).render_default_page();' - 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: light:
- platform: binary - platform: binary
name: Light name: Light
@@ -179,10 +104,6 @@ light:
output: relay_1 output: relay_1
output: output:
- platform: ledc
id: buzzer_out
pin:
number: 21
- id: relay_1 - id: relay_1
platform: gpio platform: gpio
pin: pin:
@@ -191,62 +112,3 @@ output:
# platform: gpio # platform: gpio
# pin: # pin:
# number: 19 # 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: substitutions:
device: nspanel-dev device: nspanel-dev
name: NSPanel DEV name: NSPanel DEV
@@ -37,6 +51,7 @@ esp32:
framework: framework:
type: esp-idf type: esp-idf
advanced: advanced:
flash_chip: generic
minimum_chip_revision: 3.0 minimum_chip_revision: 3.0
sram1_as_iram: true sram1_as_iram: true
@@ -59,6 +74,8 @@ external_components:
packages: packages:
common: !include common/common.yaml 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 # common: !include common/common_dev.yaml
# web_server: # web_server:
@@ -440,6 +457,13 @@ nspanel_lovelace:
- name: Rast trávy - name: Rast trávy
entity_id: automation.irrigation_grow_grass entity_id: automation.irrigation_grow_grass
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.nspanel_dev_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
name: Left Button name: Left Button
@@ -540,11 +564,6 @@ sensor:
- platform: template - platform: template
id: room_temperature_id id: room_temperature_id
time:
platform: homeassistant
id: ha_time
timezone: Europe/Bratislava
text_sensor: text_sensor:
- platform: homeassistant - platform: homeassistant
id: name_day 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: substitutions:
device: nspanel-fireplace device: nspanel-fireplace
name: Fireplace NSPanel name: Fireplace NSPanel
@@ -10,93 +24,17 @@ esphome:
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} 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: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
api: nspanel: !include
homeassistant_services: true file: common/nspanel.yaml
homeassistant_states: true vars:
actions: temperature_entity: sensor.zigbee_living_room_kitchen_temperature
- action: play_rtttl temperature_name: Living Room Temperature
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: 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: cards:
- type: cardGrid - type: cardGrid
title: Kuchyňa / Obývačka title: Kuchyňa / Obývačka
@@ -185,10 +123,12 @@ nspanel_lovelace:
- name: Auto-zatváranie - name: Auto-zatváranie
entity_id: switch.gate_auto_close entity_id: switch.gate_auto_close
time: - type: cardEntities
- platform: homeassistant title: Info
id: ha_time entities:
timezone: Europe/Bratislava - name: Zariadenie
entity_id: button.fireplace_nspanel_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
@@ -240,11 +180,6 @@ binary_sensor:
entity_id: light.mcu_kitchen_stove entity_id: light.mcu_kitchen_stove
- lambda: 'id(nspanel_id).render_default_page();' - lambda: 'id(nspanel_id).render_default_page();'
- lambda: 'id(nspanel_id).render_next_page();' - lambda: 'id(nspanel_id).render_next_page();'
output:
- platform: ledc
id: buzzer_out
pin:
number: 21
switch: switch:
- platform: gpio - platform: gpio
@@ -259,47 +194,3 @@ switch:
entity_category: config entity_category: config
pin: pin:
number: 19 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: substitutions:
device: nspanel-office-j device: nspanel-office-j
name: Office J NSPanel name: Office J NSPanel
@@ -10,93 +24,21 @@ esphome:
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} 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: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
api: nspanel: !include
homeassistant_services: true file: common/nspanel.yaml
homeassistant_states: true vars:
actions: temperature_entity: sensor.zigbee_office_j_temperature
- action: play_rtttl ntc_reference_temperature: 22°C
variables: sleep_dim: !include
song: string file: common/nspanel_sleep_dim.yaml
then: vars:
- rtttl.play: sleep_override_entity: light.office_j_lights
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: 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: cards:
- type: cardGrid - type: cardGrid
title: Janko title: Janko
@@ -134,10 +76,12 @@ nspanel_lovelace:
- name: Auto-zatváranie - name: Auto-zatváranie
entity_id: switch.gate_auto_close entity_id: switch.gate_auto_close
time: - type: cardEntities
- platform: homeassistant title: Info
id: ha_time entities:
timezone: Europe/Bratislava - name: Zariadenie
entity_id: button.office_j_nspanel_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
@@ -162,11 +106,6 @@ binary_sensor:
- lambda: 'id(nspanel_id).render_default_page();' - lambda: 'id(nspanel_id).render_default_page();'
output: output:
- platform: ledc
id: buzzer_out
pin:
number: 21
- id: relay_1 - id: relay_1
platform: gpio platform: gpio
pin: pin:
@@ -185,48 +124,3 @@ light:
# # - platform: binary # # - platform: binary
# # name: Relay 2 # # name: Relay 2
# # output: 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();
+26 -133
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: substitutions:
device: nspanel-office-r device: nspanel-office-r
name: Office R NSPanel name: Office R NSPanel
@@ -10,33 +24,15 @@ esphome:
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} 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: packages:
common: !include common/common.yaml 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: script:
- id: geiger_click - id: geiger_click
@@ -55,65 +51,7 @@ script:
return esphome::random_uint32() % 450 + 50; return esphome::random_uint32() % 450 + 50;
- script.execute: geiger_click - 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: 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: cards:
- type: cardGrid - type: cardGrid
title: Romanko title: Romanko
@@ -158,10 +96,12 @@ nspanel_lovelace:
- name: Auto-zatváranie - name: Auto-zatváranie
entity_id: switch.gate_auto_close entity_id: switch.gate_auto_close
time: - type: cardEntities
- platform: homeassistant title: Info
id: ha_time entities:
timezone: Europe/Bratislava - name: Zariadenie
entity_id: button.office_r_nspanel_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
@@ -186,10 +126,6 @@ binary_sensor:
- lambda: 'id(nspanel_id).render_default_page();' - lambda: 'id(nspanel_id).render_default_page();'
output: output:
- platform: ledc
id: buzzer_out
pin:
number: 21
- id: relay_1 - id: relay_1
platform: gpio platform: gpio
pin: pin:
@@ -229,14 +165,6 @@ switch:
id: relay_2 id: relay_2
pin: pin:
number: 19 number: 19
- platform: gpio
name: Screen Power
id: screen_power
entity_category: config
pin:
number: 4
inverted: true
restore_mode: ALWAYS_ON
- platform: template - platform: template
name: "Geiger Counter" name: "Geiger Counter"
optimistic: True optimistic: True
@@ -244,38 +172,3 @@ switch:
- script.execute: geiger_click - script.execute: geiger_click
turn_off_action: turn_off_action:
- script.stop: geiger_click - 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: substitutions:
device: nspanel-patio device: nspanel-patio
name: Patio NSPanel name: Patio NSPanel
@@ -10,96 +24,21 @@ esphome:
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} 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: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
api: nspanel: !include
homeassistant_services: true file: common/nspanel.yaml
homeassistant_states: true vars:
actions: temperature_entity: sensor.zigbee_living_room_kitchen_temperature
- action: play_rtttl temperature_name: Living Room Temperature
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: 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: cards:
- type: cardGrid - type: cardGrid
title: Kuchyňa / Obývačka title: Kuchyňa / Obývačka
id: card_home
entities: entities:
- name: Kuchyňa / Obývačka - name: Kuchyňa / Obývačka
entity_id: light.kitchen entity_id: light.kitchen
@@ -132,6 +71,7 @@ nspanel_lovelace:
- type: cardGrid - type: cardGrid
title: Von title: Von
id: card_outside
entities: entities:
- name: Terasa - name: Terasa
entity_id: light.patio_lights entity_id: light.patio_lights
@@ -214,10 +154,12 @@ nspanel_lovelace:
- name: Rast trávy - name: Rast trávy
entity_id: automation.irrigation_grow_grass entity_id: automation.irrigation_grow_grass
time: - type: cardEntities
- platform: homeassistant title: Info
id: ha_time entities:
timezone: Europe/Bratislava - name: Zariadenie
entity_id: button.patio_nspanel_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
@@ -227,9 +169,7 @@ binary_sensor:
inverted: true inverted: true
on_click: on_click:
- switch.toggle: relay_1 - switch.toggle: relay_1
- lambda: 'id(nspanel_id).render_default_page();' - script.execute: show_outside_card
- lambda: 'id(nspanel_id).render_next_page();'
- lambda: 'id(nspanel_id).render_next_page();'
- platform: gpio - platform: gpio
name: Right Button name: Right Button
@@ -238,24 +178,23 @@ binary_sensor:
inverted: true inverted: true
on_click: on_click:
if: if:
# mcu-patio online -> toggle its lights; otherwise (no API or relay_2 cut its power) the relay
condition: condition:
api.connected: and:
- api.connected:
- binary_sensor.is_on: patio_status
then: then:
- homeassistant.action: - homeassistant.action:
action: light.toggle action: light.toggle
data: data:
entity_id: light.patio_lights entity_id: light.patio_lights
- lambda: 'id(nspanel_id).render_default_page();' - script.execute: show_outside_card
- lambda: 'id(nspanel_id).render_next_page();'
- lambda: 'id(nspanel_id).render_next_page();'
else: else:
- switch.toggle: relay_2 - switch.toggle: relay_2
output: - platform: homeassistant
- platform: ledc id: patio_status
id: buzzer_out entity_id: binary_sensor.mcu_patio_status
pin:
number: 21
switch: switch:
- platform: gpio - platform: gpio
@@ -272,46 +211,12 @@ switch:
pin: pin:
number: 19 number: 19
- platform: gpio script:
name: Screen Power # jump straight to the "Von" card (one render instead of home + next + next):
id: screen_power # make it the default page for a moment, render it, restore the home card
entity_category: config - id: show_outside_card
pin: then:
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: |- - lambda: |-
id(nspanel_id).set_time_format("%H:%M~" + x); id(nspanel_id).set_default_page("card_outside");
id(nspanel_id).update_time(); 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: substitutions:
device: office-r device: office-r
name: Office R name: Office R
@@ -18,17 +29,13 @@ esp32:
variant: esp32c3 variant: esp32c3
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: generic
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# GPIO21 UART TX
# GPIO20 UART RX
# GPIO0 I2C SDA
# GPIO1 I2C SCL
# GPIO2 NEO
# GPIO3 BUTTON
light: light:
- platform: rgb - 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: substitutions:
device: patio device: patio
name: Patio name: Patio
@@ -33,32 +50,16 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml 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: i2c:
# - id: i2c0 # - id: i2c0
# sda: 26 # 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: substitutions:
device: pow-dishwasher device: pow-dishwasher
name: Dishwasher POW name: Dishwasher POW
@@ -18,11 +30,13 @@ esp32:
framework: framework:
type: esp-idf type: esp-idf
advanced: advanced:
flash_chip: gd
minimum_chip_revision: 3.1 minimum_chip_revision: 3.1
sram1_as_iram: true sram1_as_iram: true
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
uart: uart:
- id: cse7766_uart - id: cse7766_uart
@@ -186,6 +200,3 @@ switch:
- delay: 500ms - delay: 500ms
- switch.turn_off: relay_off # bi-stable relay so no need to keep on - switch.turn_off: relay_off # bi-stable relay so no need to keep on
interlock: [relay_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: substitutions:
device: pow-washer device: pow-washer
name: Washer POW name: Washer POW
comment: comment: "spare"
area: Washroom area: Washroom
update_interval: 10s update_interval: 10s
@@ -18,6 +30,7 @@ esp32:
framework: framework:
type: esp-idf type: esp-idf
advanced: advanced:
flash_chip: gd # same device as pow-dishwasher (not read from the device)
minimum_chip_revision: 3.1 minimum_chip_revision: 3.1
sram1_as_iram: true sram1_as_iram: true
@@ -186,6 +199,3 @@ switch:
- delay: 500ms - delay: 500ms
- switch.turn_off: relay_off # bi-stable relay so no need to keep on - switch.turn_off: relay_off # bi-stable relay so no need to keep on
interlock: [relay_on] interlock: [relay_on]
time:
- !include common/time/homeassistant.yaml
+15
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: substitutions:
device: rf device: rf
name: RF Bridge name: RF Bridge
@@ -15,10 +26,14 @@ esp32:
variant: esp32 variant: esp32
flash_size: 4MB flash_size: 4MB
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
spi: spi:
clk_pin: 23 clk_pin: 23
+6
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: substitutions:
device: rf433 device: rf433
name: RF433 Bridge name: RF433 Bridge
@@ -13,6 +18,7 @@ esphome:
esp8266: esp8266:
board: esp01_1m board: esp01_1m
toolchain: arduino
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
+273
View File
@@ -0,0 +1,273 @@
---
# Hardware: M5Stack M5Stamp S3 + PN5180 module (5 V and 3.3 V both needed)
# Pinout:
# GPIO0 Button
# GPIO3 (external RFID LED, not fitted yet; notify_led uses the onboard RGB for now)
# GPIO4 Buzzer -> buzzer (output ledc)
# GPIO5 -> spi (spi miso_pin) PN5180 MISO
# GPIO6 -> spi (spi mosi_pin) PN5180 MOSI
# GPIO7 -> spi (spi clk_pin) PN5180 SCK
# GPIO8 -> pn5180 (cs_pin) PN5180 NSS
# GPIO9 -> pn5180 (busy_pin) PN5180 BUSY
# GPIO10 -> pn5180 (reset_pin) PN5180 RST
# GPIO11 -> pn5180 (irq_pin) PN5180 IRQ
# GPIO19 U-
# GPIO20 U+
# GPIO21 RGB -> notify_led (light esp32_rmt_led_strip), also status_led
# PN5180 REQ, AUX, GPIO left open (REQ high at reset = firmware download mode)
substitutions:
device: rfid-openprinttag
name: OpenPrintTag
area: DEV
comment: Filament spool reader (OpenPrintTag, Creality CFS)
esphome:
name: mcu-${device}
friendly_name: ${name}
area: ${area}
comment: ${comment}
esp32:
variant: esp32s3
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: notify_led
show_errors: "true"
external_components:
- source: github://randybb/esphome-components
components: [pn5180, openprinttag, creality_cfs]
refresh: 1h
# Called by the OpenPrintTag integration (openprinttag.update) to update the aux region
api:
actions:
- action: openprinttag_write_aux
variables:
uid: string
aux: string
then:
- if:
condition:
switch.is_on: led_enabled
then:
- light.turn_on:
id: notify_led
brightness: 100%
red: 100%
green: 0%
blue: 0%
flash_length: 500ms
- lambda: id(spool).write_aux(uid, aux);
# Writes a Creality CFS record (48 characters, optionally 48 more for sector 2) to the
# Creality tag on the reader
- action: creality_cfs_write
variables:
uid: string
data: string
then:
- if:
condition:
switch.is_on: led_enabled
then:
- light.turn_on:
id: notify_led
brightness: 100%
red: 100%
green: 0%
blue: 0%
flash_length: 500ms
- lambda: id(creality).write(uid, data);
spi:
clk_pin: GPIO7
mosi_pin: GPIO6
miso_pin: GPIO5
pn5180:
id: pn5180_reader
cs_pin: GPIO8
busy_pin: GPIO9
reset_pin: GPIO10
irq_pin: GPIO11
on_tag:
- if:
condition:
switch.is_on: led_enabled
then:
- light.turn_on:
id: notify_led
brightness: 100%
red: 0%
green: 100%
blue: 0%
flash_length: 500ms
- if:
condition:
switch.is_on: buzzer_enabled
then:
- rtttl.play: "success:d=32,o=5,b=100:c,g,b"
- homeassistant.tag_scanned: !lambda return x;
on_tag_removed:
- if:
condition:
switch.is_on: buzzer_enabled
then:
- rtttl.play: "removed:d=16,o=5,b=100:b"
openprinttag:
id: spool
# Raw tag record for the OpenPrintTag integration (randybb/ha-openprinttag), empty when removed
on_openprinttag:
- homeassistant.event:
event: esphome.openprinttag
data:
uid: !lambda return uid;
payload: !lambda return payload;
creality_cfs:
id: creality
# The Creality record (ASCII) for Home Assistant, empty when removed
on_creality:
- homeassistant.event:
event: esphome.creality_cfs
data:
uid: !lambda return uid;
data: !lambda return data;
sensor:
- platform: creality_cfs
name: Creality length
- platform: openprinttag
type: remaining_weight
name: Remaining weight
- platform: openprinttag
type: consumed_weight
name: Consumed weight
- platform: openprinttag
type: actual_weight
name: Full weight
- platform: openprinttag
type: min_print_temperature
name: Min print temperature
- platform: openprinttag
type: max_print_temperature
name: Max print temperature
- platform: openprinttag
type: max_bed_temperature
name: Max bed temperature
- platform: openprinttag
type: drying_temperature
name: Drying temperature
- platform: openprinttag
type: drying_time
name: Drying time
text_sensor:
- platform: pn5180
name: Tag UID
- platform: creality_cfs
type: material_id
name: Creality material ID
- platform: creality_cfs
type: color
name: Creality color
- platform: creality_cfs
type: serial
name: Creality serial
- platform: openprinttag
type: material_type
name: Material
- platform: openprinttag
type: material_name
name: Material name
- platform: openprinttag
type: brand_name
name: Brand
- platform: openprinttag
type: primary_color
name: Color
# Mirrored to the filament_color light, empty = no tag
on_value:
- lambda: |-
if (x.size() < 7) {
id(filament_color).turn_off().set_transition_length(0).perform();
return;
}
uint32_t c = strtoul(x.c_str() + 1, nullptr, 16);
if (x.size() > 7)
c >>= 8; // #rrggbbaa
// ESPHome scales the strongest channel to 100 %, the darkness goes to the brightness
const float r = ((c >> 16) & 0xFF) / 255.0f, g = ((c >> 8) & 0xFF) / 255.0f, b = (c & 0xFF) / 255.0f;
const float m = std::max({r, g, b});
if (m == 0.0f) {
id(filament_color).turn_off().set_transition_length(0).perform(); // black
return;
}
id(filament_color).turn_on()
.set_rgb(r, g, b)
.set_brightness(m)
.set_transition_length(0)
.perform();
light:
# Onboard RGB for now: tag feedback and status. With the external LED fitted, move
# notify_led to pin 3 and give the onboard one back to status_led (as on mcu-rfid-reader)
- platform: esp32_rmt_led_strip
id: notify_led
name: Notify LED
channel_colors: GRB
pin: 21
num_leds: 1
chipset: ws2812
restore_mode: ALWAYS_OFF
rmt_symbols: 96
# Shows the filament color in Home Assistant; drives nothing, the next tag read overwrites it
- platform: rgb
id: filament_color
name: Filament color
icon: mdi:printer-3d-nozzle
red: color_none
green: color_none
blue: color_none
restore_mode: ALWAYS_OFF
default_transition_length: 0s
output:
- platform: ledc
pin: 4
id: buzzer
- platform: template
id: color_none
type: float
write_action: []
rtttl:
output: buzzer
switch:
- platform: template
name: Buzzer Enabled
id: buzzer_enabled
icon: mdi:volume-high
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
entity_category: config
- platform: template
name: LED enabled
id: led_enabled
icon: mdi:alarm-light-outline
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
entity_category: config
+27 -21
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: substitutions:
device: rfid-reader device: rfid-reader
name: RFID Reader name: RFID Reader
@@ -16,7 +28,7 @@ esphome:
# - wait_until: # - wait_until:
# api.connected: # api.connected:
# - logger.log: API is connected! # - logger.log: API is connected!
# - rtttl.play: "success:d=24,o=5,b=100:c,g,b" # - rtttl.play: "success:d=32,o=5,b=100:c,g,b"
# - light.turn_on: # - light.turn_on:
# id: notify_led # id: notify_led
# brightness: 100% # brightness: 100%
@@ -31,6 +43,8 @@ esp32:
variant: esp32s3 variant: esp32s3
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
# external_components: # external_components:
@@ -40,19 +54,11 @@ esp32:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
# logger: # logger:
# hardware_uart: UART0 # hardware_uart: UART0
# GPIO20 U+
# GPIO19 U-
# GPIO0 Button
# GPIO1 I2C SDA
# GPIO2 I2C SDA
# GPIO2 Notify LED
# GPIO4 Buzzer
# GPIO21 RGB
api: api:
actions: actions:
- action: rfidreader_tag_ok - action: rfidreader_tag_ok
@@ -85,13 +91,13 @@ api:
uri += tag_id; uri += tag_id;
message->add_uri_record(uri); message->add_uri_record(uri);
id(pn532_module).write_mode(message); id(pn532_module).write_mode(message);
- rtttl.play: "write:d=24,o=5,b=100:b" - rtttl.play: "write:d=32,o=5,b=100:b"
- wait_until: - wait_until:
not: not:
pn532.is_writing: pn532.is_writing:
- light.turn_off: - light.turn_off:
id: notify_led id: notify_led
- rtttl.play: "write:d=24,o=5,b=100:b,b" - rtttl.play: "write:d=32,o=5,b=100:b,b"
- action: write_music_tag - action: write_music_tag
variables: variables:
@@ -117,13 +123,13 @@ api:
message->add_text_record(text); message->add_text_record(text);
} }
id(pn532_module).write_mode(message); id(pn532_module).write_mode(message);
- rtttl.play: "write:d=24,o=5,b=100:b" - rtttl.play: "write:d=32,o=5,b=100:b"
- wait_until: - wait_until:
not: not:
pn532.is_writing: pn532.is_writing:
- light.turn_off: - light.turn_off:
id: notify_led id: notify_led
- rtttl.play: "write:d=24,o=5,b=100:b,b" - rtttl.play: "write:d=32,o=5,b=100:b,b"
globals: globals:
- id: source - id: source
@@ -165,7 +171,7 @@ pn532_i2c:
id(info)=""; id(info)="";
if (tag.has_ndef_message()) { if (tag.has_ndef_message()) {
auto message = tag.get_ndef_message(); auto message = tag.get_ndef_message();
auto records = message->get_records(); const auto &records = message->get_records();
for (auto &record : records) { for (auto &record : records) {
std::string payload = record->get_payload(); std::string payload = record->get_payload();
std::string type = record->get_type(); std::string type = record->get_type();
@@ -265,7 +271,7 @@ pn532_i2c:
condition: condition:
switch.is_on: buzzer_enabled switch.is_on: buzzer_enabled
then: then:
- rtttl.play: "success:d=24,o=5,b=100:c,g,b" - rtttl.play: "success:d=32,o=5,b=100:c,g,b"
on_tag_removed: on_tag_removed:
then: then:
- homeassistant.event: - homeassistant.event:
@@ -307,13 +313,13 @@ button:
message->add_uri_record(uri); message->add_uri_record(uri);
ESP_LOGD("tagreader", "Writing payload: %s", uri.c_str()); ESP_LOGD("tagreader", "Writing payload: %s", uri.c_str());
id(pn532_module).write_mode(message); id(pn532_module).write_mode(message);
- rtttl.play: "write:d=24,o=5,b=100:b" - rtttl.play: "write:d=32,o=5,b=100:b"
- wait_until: - wait_until:
not: not:
pn532.is_writing: pn532.is_writing:
- light.turn_off: - light.turn_off:
id: notify_led id: notify_led
- rtttl.play: "write:d=24,o=5,b=100:b,b" - rtttl.play: "write:d=32,o=5,b=100:b,b"
- platform: template - platform: template
name: Clean Tag name: Clean Tag
id: clean_tag id: clean_tag
@@ -327,13 +333,13 @@ button:
green: 64.7% green: 64.7%
blue: 0% blue: 0%
- lambda: 'id(pn532_module).clean_mode();' - lambda: 'id(pn532_module).clean_mode();'
- rtttl.play: "write:d=24,o=5,b=100:b" - rtttl.play: "write:d=32,o=5,b=100:b"
- wait_until: - wait_until:
not: not:
pn532.is_writing: pn532.is_writing:
- light.turn_off: - light.turn_off:
id: notify_led id: notify_led
- rtttl.play: "write:d=24,o=5,b=100:b,b" - rtttl.play: "write:d=32,o=5,b=100:b,b"
- platform: template - platform: template
name: Cancel writing name: Cancel writing
id: cancel_writing id: cancel_writing
@@ -343,7 +349,7 @@ button:
- lambda: 'id(pn532_module).read_mode();' - lambda: 'id(pn532_module).read_mode();'
- light.turn_off: - light.turn_off:
id: notify_led id: notify_led
- rtttl.play: "write:d=24,o=5,b=100:b,b" - rtttl.play: "write:d=32,o=5,b=100:b,b"
light: light:
- platform: esp32_rmt_led_strip - platform: esp32_rmt_led_strip
+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: substitutions:
device: shed device: shed
name: Shed name: Shed
@@ -15,12 +26,16 @@ esp32:
variant: esp32 variant: esp32
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: gd
type: esp-idf type: esp-idf
# version: 5.4.2 # version: 5.4.2
# platform_version: 54.03.21 # platform_version: 54.03.21
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
i2c: i2c:
sda: 25 sda: 25
@@ -108,6 +123,3 @@ switch:
pin: pin:
number: 19 number: 19
mode: OUTPUT mode: OUTPUT
time:
- !include common/time/homeassistant.yaml
+13 -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: substitutions:
device: socket-01 device: socket-01
name: Socket 01 name: Socket 01
@@ -15,22 +26,11 @@ esphome:
esp8266: esp8266:
board: esp01_1m board: esp01_1m
toolchain: arduino
packages: packages:
common: !include common/common_esp8266.yaml 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: binary_sensor:
- platform: gpio - platform: gpio
pin: pin:
@@ -121,8 +121,7 @@ switch:
# number: GPIO00 # number: GPIO00
# inverted: True # inverted: True
time: # time:
- !include common/time/homeassistant.yaml
# - platform: homeassistant # - platform: homeassistant
# timezone: Europe/Bratislava # timezone: Europe/Bratislava
# on_time: # on_time:
+13 -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: substitutions:
device: socket-02 device: socket-02
name: Socket 02 name: Socket 02
@@ -15,22 +26,11 @@ esphome:
esp8266: esp8266:
board: esp01_1m board: esp01_1m
toolchain: arduino
packages: packages:
common: !include common/common_esp8266.yaml 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: binary_sensor:
- platform: gpio - platform: gpio
pin: pin:
@@ -122,8 +122,7 @@ switch:
on_turn_off: on_turn_off:
- light.turn_off: light_red - light.turn_off: light_red
time: # time:
- !include common/time/homeassistant.yaml
# - platform: homeassistant # - platform: homeassistant
# timezone: Europe/Bratislava # timezone: Europe/Bratislava
# on_time: # on_time:
+14 -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: substitutions:
device: socket-03 device: socket-03
name: Socket 03 name: Socket 03
@@ -19,24 +30,14 @@ esphome:
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} comment: ${comment}
esp8266: esp8266:
board: esp01_1m board: esp01_1m
toolchain: arduino
packages: packages:
common: !include common/common_esp8266.yaml 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: binary_sensor:
- platform: gpio - platform: gpio
pin: pin:
@@ -144,8 +145,7 @@ switch:
# number: GPIO00 # number: GPIO00
# inverted: True # inverted: True
time: # time:
- !include common/time/homeassistant.yaml
# - platform: homeassistant # - platform: homeassistant
# timezone: Europe/Bratislava # timezone: Europe/Bratislava
# on_time: # on_time:
+66 -10
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: substitutions:
device: stackchan device: stackchan
name: StackChan name: StackChan
@@ -25,6 +65,8 @@ esp32:
flash_size: 16MB flash_size: 16MB
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: generic
type: esp-idf type: esp-idf
psram: psram:
@@ -33,6 +75,7 @@ psram:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
external_components: external_components:
- source: github://m5stack/esphome-yaml/components - source: github://m5stack/esphome-yaml/components
@@ -40,7 +83,7 @@ external_components:
refresh: 0s refresh: 0s
- source: github://randybb/esphome-components - source: github://randybb/esphome-components
components: [audio_spectrum] components: [audio_spectrum]
refresh: 1d refresh: 1h
globals: globals:
- id: in_love - id: in_love
@@ -464,9 +507,9 @@ spi:
image: image:
- platform: file - platform: file
file: assets/images/esphome-logo-text-on-dark.svg file: assets/images/made-for-esphome-white-on-black.svg
id: esphome_logo id: esphome_logo
resize: 280x56 resize: 230x68
type: RGB565 type: RGB565
transparency: alpha_channel transparency: alpha_channel
- platform: file - platform: file
@@ -545,22 +588,36 @@ display:
if (id(show_status)) { if (id(show_status)) {
first_draw = true; first_draw = true;
it.fill(id(face_bg)); 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}"); it.print(160, 95, id(font_title), id(face_fg), TextAlign::CENTER, "${name}");
if (wifi_ok) { if (wifi_ok) {
it.printf(20, 135, id(font_status), id(status_ok), "WiFi: %s (%d dBm)", it.printf(20, 114, id(font_status), id(status_ok), "WiFi: connected (%d dBm)", rssi);
id(ip_address_sensor).state.c_str(), 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 { } 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(); 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..."); api_ok ? "Home Assistant: connected" : "Home Assistant: waiting...");
if (batt >= 0) { 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)" : ""); "Battery: %d%%%s", batt, charging ? " (charging)" : "");
} }
it.printf(20, 212, id(font_status), id(status_dim), "ESPHome %s", ESPHOME_VERSION); it.printf(20, 212, id(font_status), id(status_dim), "ESPHome %s", ESPHOME_VERSION);
@@ -883,4 +940,3 @@ time:
id: rtc_time id: rtc_time
i2c_id: i2c_bsp i2c_id: i2c_bsp
update_interval: never update_interval: never
- !include common/time/homeassistant.yaml
+5
View File
@@ -1,4 +1,8 @@
--- ---
# Hardware: Sonoff Mini
# Pinout:
# GPIO12 -> relay (output gpio)
# GPIO13 -> led_blue (output gpio)
substitutions: substitutions:
device: staircase-light device: staircase-light
name: Staircase name: Staircase
@@ -13,6 +17,7 @@ esphome:
esp8266: esp8266:
board: esp01_1m board: esp01_1m
toolchain: arduino
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
+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: substitutions:
device: tft device: tft
name: TFT name: TFT
@@ -10,104 +20,258 @@ esphome:
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} comment: ${comment}
platformio_options: on_boot:
board_build.flash_mode: dio - priority: -100
then:
- lvgl.page.show: status_page
esp32: esp32:
variant: esp32c3 variant: esp32c3
framework: framework:
advanced:
flash_chip: generic
type: esp-idf type: esp-idf
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
logger: api:
logs: # status page until Home Assistant connects (log viewers don't subscribe to states)
component: ERROR on_client_connected:
- delay: 2s
# GPIO1 UART TX - if:
# GPIO3 UART RX condition:
# GPIO4 I2C SDA api.connected:
# GPIO5 I2C SCL state_subscription_only: true
# GPIO12 DISPLAY DIO then:
# GPIO12 DISPLAY CLOCK - lvgl.page.show: main_page
# GPIO14 BUZZER on_client_disconnected:
# GPIO16 RGB - if:
condition:
not:
api.connected:
state_subscription_only: true
then:
- lvgl.page.show: status_page
spi: spi:
clk_pin: 4 clk_pin: 4
mosi_pin: 5 mosi_pin: 5
miso_pin: 6 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: display:
- platform: mipi_spi - platform: mipi_spi
id: main_display
model: ILI9341 model: ILI9341
cs_pin: 7 cs_pin: 7
dc_pin: 8 dc_pin: 8
reset_pin: 10 reset_pin: 10
invert_colors: false invert_colors: false
lambda: |- data_rate: 40MHz
it.fill(Color::BLACK); update_interval: never
it.print(0, 0, id(b612_12), id(my_white), TextAlign::TOP_LEFT, "HELLO WORLD!"); auto_clear_enabled: false
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!"); touchscreen:
it.print(0, 42, id(b612_12), id(my_red), TextAlign::TOP_LEFT, "HELLO WORLD!"); - 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: substitutions:
device: tracker device: tracker
name: Tracker name: Tracker
+19 -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: substitutions:
device: tv-light device: tv-light
name: TV Light name: TV Light
@@ -13,20 +31,11 @@ esphome:
esp8266: esp8266:
board: esp8285 board: esp8285
toolchain: arduino
packages: packages:
common: !include common/common_esp8266.yaml 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: light:
- platform: status_led - platform: status_led
id: status_led_id id: status_led_id
+2
View File
@@ -1,4 +1,6 @@
--- ---
# Hardware: M5Stack ATOM Lite
# Pinout: see common/vehicle_base.yaml
substitutions: substitutions:
device: vehicle-honda-pcx125 device: vehicle-honda-pcx125
name: 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: substitutions:
device: vehicle-suzuki-dl650 device: vehicle-suzuki-dl650
name: 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: substitutions:
device: vehicle-toyota-auris-ts device: vehicle-toyota-auris-ts
name: 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: substitutions:
device: vehicle-toyota-yaris-cross device: vehicle-toyota-yaris-cross
name: Vehicle Toyota Yaris Cross name: Vehicle Toyota Yaris Cross
+8 -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: substitutions:
device: waterproof-socket device: waterproof-socket
name: Waterproof Socket name: Waterproof Socket
@@ -13,17 +20,11 @@ esphome:
esp8266: esp8266:
board: esp01_1m board: esp01_1m
toolchain: arduino
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
# Sonoff Basic R2
# GPIO00 - BUTTON
# GPIO12 - RELAY
# GPIO13 - LED1
# GPIO03 - RX PIN
# GPIO01 - TX PIN
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
pin: 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: substitutions:
device: well device: well
name: Well name: Well
@@ -30,10 +41,13 @@ esp32:
framework: framework:
type: esp-idf type: esp-idf
advanced: advanced:
flash_chip: gd
sram1_as_iram: true sram1_as_iram: true
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
api: api:
actions: actions:
@@ -357,6 +371,3 @@ valve:
- switch.turn_on: irrigation_relay_8 - switch.turn_on: irrigation_relay_8
close_action: close_action:
- switch.turn_off: irrigation_relay_8 - switch.turn_off: irrigation_relay_8
time:
- !include common/time/homeassistant.yaml
+9
View File
@@ -1,6 +1,9 @@
wifi_ssid: "ssid" wifi_ssid: "ssid"
wifi_password: "password" wifi_password: "password"
wifi_ssid_ipv6: "ssid"
wifi_password_ipv6: "password"
api_password: "password" api_password: "password"
api_key: "oSsCFxRUqIJLpT98cQwSwNxYoC7zbUh0YBHczAWRyBI=" api_key: "oSsCFxRUqIJLpT98cQwSwNxYoC7zbUh0YBHczAWRyBI="
@@ -26,3 +29,9 @@ ble_beacon_toyota_auris_minor: 61958
ble_beacon_toyota_yaris_uuid: "00000000-0000-0000-0000-000000000000" ble_beacon_toyota_yaris_uuid: "00000000-0000-0000-0000-000000000000"
ble_beacon_toyota_yaris_honda_major: 10167 ble_beacon_toyota_yaris_honda_major: 10167
ble_beacon_toyota_yaris_honda_minor: 61958 ble_beacon_toyota_yaris_honda_minor: 61958
# Thread active dataset (hex TLV) from Home Assistant
thread_tlv: "0E080000000000010000"
# ANT+ network key (8 bytes hex), from thisisant.com
ant_plus_network_key: "0000000000000000"