Compare commits

...
58 Commits
Author SHA1 Message Date
randy 3374ed6ad8 staircase-light: add second PIR sensor
CI / ESPHome config validation (push) Failing after 5s
CI / YAML lint (push) Failing after 19s
2026-10-10 17:50:24 +02:00
randy e5f9c5813e stackchan: 40MHz flash, the IDF 5.5.5 bootloader misreads this flash at 80MHz 2026-10-10 17:41:05 +02:00
randy 2b66f1a60d echo-1: WAV media format, decoding MP3/FLAC without PSRAM runs the heap out 2026-10-10 17:41:05 +02:00
randy 05060756e3 OpenPrintTag reader: filament color light falls back to the Creality tag
CI / ESPHome config validation (push) Failing after 6s
CI / YAML lint (push) Failing after 17s
2026-10-10 12:35:49 +02:00
randy 7cc90187d1 ipv6_only_eth: mdns 1.14.0 from the registry instead of the fork 2026-10-10 12:35:49 +02:00
randy 26a09b37bc all esp8266: LEAmDNS fork announcing IPv6 addresses (esp8266/Arduino#9068) 2026-10-10 12:33:12 +02:00
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
86 changed files with 118460 additions and 955 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
Submodule common/.esphome/external_components/b7dc7eea deleted from 16571e8a90.
+10
View File
@@ -0,0 +1,10 @@
---
# ESP8266 core with LEAmDNS announcing the IPv6 addresses (AAAA, ff02::fb) from
# randybb/Arduino@mdns-ipv6-aaaa (esp8266/Arduino#9068); add next to common_esp8266.yaml.
# The device must not set 'toolchain: arduino' (no custom framework source there).
# Drop once it's upstream and in an ESPHome release.
esp8266:
toolchain: platformio
framework:
version: 3.1.2
source: https://github.com/randybb/Arduino.git#mdns-ipv6-aaaa
+3 -27
View File
@@ -3,36 +3,12 @@
# packages: # packages:
# common: !include common/common.yaml # common: !include common/common.yaml
# ipv6_only: !include common/ipv6_only.yaml # ipv6_only: !include common/ipv6_only.yaml
external_components: # Ethernet devices use common/ipv6_only_eth.yaml (this without the WiFi part)
# network enable_ipv4 (esphome/esphome#19750), drop once merged packages:
- source: github://pr#19750 base: !include ipv6_only_eth.yaml
components: [const, network, wifi]
# audio HTTP reader over IPv6 (dual-stack hosts resolve A first), drop once in #19750
- source: github://randybb/esphome-components
components: [audio]
refresh: 1d
wifi: wifi:
networks: networks:
- id: !extend wifi_iot - id: !extend wifi_iot
ssid: !secret wifi_ssid_ipv6 ssid: !secret wifi_ssid_ipv6
password: !secret wifi_password_ipv6 password: !secret wifi_password_ipv6
esp32:
framework:
components:
# mdns 1.12.0 + fix for "A 0.0.0.0" without IPv4 (espressif/esp-protocols PR pending), drop once released
- name: espressif/mdns
source: https://github.com/randybb/esp-protocols.git
ref: mdns-v1.12.0-zero-ipv4-test
path: components/mdns
# IDF v5.5.5 lwip + .local resolution over IPv6 (espressif/esp-lwip#94), drop once in IDF
- name: lwip
source: https://github.com/randybb/esp-lwip.git
ref: idf-v5.5.5-lwip-component
path: lwip
network:
enable_ipv6: true
enable_ipv4: false
min_ipv6_addr_count: 1
+29
View File
@@ -0,0 +1,29 @@
---
# 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]
refresh: 1h
esp32:
framework:
components:
# mdns 1.14.0: no "A 0.0.0.0" without IPv4 + IPv6 on ETH-only builds (espressif/esp-protocols#1156, #1161),
# drop once on ESPHome 2026.10.0 (esphome/esphome#20383 bumps the pin from 1.12.0)
- name: espressif/mdns
ref: 1.14.0
# 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
+4
View File
@@ -28,9 +28,13 @@ 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
packages:
popup: !include nspanel_popup.yaml
external_components: external_components:
- source: - source:
type: git type: git
+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
+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:
+1
View File
@@ -9,3 +9,4 @@ wifi:
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
-176
View File
@@ -1,176 +0,0 @@
#pragma once
// Hourly weather forecast for mcu-m5paper: parsed from the weather.get_forecasts
// response and kept in the on-board FM24C02 EEPROM (256 B, I2C 0x50), so it
// survives the power-off between RTC wake-ups.
#include <cmath>
#include <cstdio>
#include <cstring>
#include "esphome/components/i2c/i2c_bus.h"
#include "esphome/components/json/json_util.h"
#include "esphome/core/hal.h"
namespace m5paper_weather {
static constexpr uint8_t EEPROM_ADDR = 0x50;
static constexpr uint8_t EEPROM_PAGE = 8;
static constexpr uint8_t MAGIC = 0xA5;
static constexpr uint8_t VERSION = 1;
static constexpr uint8_t MAX_HOURS = 48;
// magic, version, fetched_at (u32), first_ts (u32), count
static constexpr size_t HEADER = 11;
static constexpr size_t MAX_SIZE = HEADER + MAX_HOURS * 4;
static_assert(MAX_SIZE <= 256, "forecast does not fit into the EEPROM");
static constexpr uint8_t NO_VALUE = 0xFF;
static constexpr int8_t NO_TEMP = INT8_MIN;
struct Hour {
uint8_t cond; // index into CONDITIONS, NO_VALUE if unknown
int8_t temp2; // temperature in 0.5 °C, NO_TEMP if unknown
uint8_t wind; // km/h, NO_VALUE if unknown
uint8_t pop; // precipitation probability %, NO_VALUE if unknown
};
static_assert(sizeof(Hour) == 4, "Hour must stay 4 bytes");
struct Forecast {
uint32_t fetched_at{0}; // UTC epoch of the download
uint32_t first_ts{0}; // UTC epoch of hours[0]; entries are 1 h apart
uint8_t count{0};
Hour hours[MAX_HOURS]{};
bool valid() const { return this->count > 0; }
// hour covering the given UTC epoch, nullptr if outside the forecast
const Hour *at(uint32_t ts) const {
if (!this->valid() || ts < this->first_ts)
return nullptr;
uint32_t idx = (ts - this->first_ts) / 3600;
return idx < this->count ? &this->hours[idx] : nullptr;
}
};
// the forecast in RAM, loaded from the EEPROM at boot
inline Forecast &forecast() {
static Forecast fc;
return fc;
}
// Home Assistant weather conditions; the index is the stored condition code
static const char *const CONDITIONS[] = {
"clear-night", "cloudy", "exceptional", "fog", "hail", "lightning", "lightning-rainy", "partlycloudy",
"pouring", "rainy", "snowy", "snowy-rainy", "sunny", "windy", "windy-variant",
};
static const char *const CONDITION_NAMES[] = {
"Jasno", "Oblačno", "Extrémne počasie", "Hmla", "Krupobitie", "Búrka", "Búrka s dažďom", "Polooblačno",
"Lejak", "Dážď", "Sneženie", "Dážď so snehom", "Slnečno", "Veterno", "Veterno, oblačno",
};
static constexpr uint8_t NUM_CONDITIONS = sizeof(CONDITIONS) / sizeof(CONDITIONS[0]);
inline uint8_t condition_code(const char *name) {
for (uint8_t i = 0; i < NUM_CONDITIONS; i++) {
if (strcmp(name, CONDITIONS[i]) == 0)
return i;
}
return NO_VALUE;
}
inline const char *condition_name(uint8_t code) { return code < NUM_CONDITIONS ? CONDITION_NAMES[code] : "?"; }
// 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;
}
// "2026-09-27T16:00:00+00:00" -> UTC epoch, 0 on error
inline uint32_t parse_iso8601(const char *s) {
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 < 5)
return 0;
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;
}
return ts > 0 ? uint32_t(ts) : 0;
}
// Parse the weather.get_forecasts response for the given entity;
// Home Assistant wraps the action response as {"response": {...}}
inline bool parse(ArduinoJson::JsonObjectConst response, const char *entity, uint32_t now, Forecast &fc) {
ArduinoJson::JsonObjectConst root = response["response"].is<ArduinoJson::JsonObjectConst>()
? response["response"].as<ArduinoJson::JsonObjectConst>()
: response;
ArduinoJson::JsonArrayConst items = root[entity]["forecast"];
if (items.isNull() || items.size() == 0)
return false;
Forecast out;
for (ArduinoJson::JsonObjectConst item : items) {
if (out.count >= MAX_HOURS)
break;
if (out.count == 0) {
out.first_ts = parse_iso8601(item["datetime"] | "");
if (out.first_ts == 0)
return false;
}
Hour &hour = out.hours[out.count++];
hour.cond = condition_code(item["condition"] | "");
float temp = item["temperature"] | NAN;
hour.temp2 = std::isnan(temp) ? NO_TEMP : int8_t(std::max(-127L, std::min(127L, lroundf(temp * 2))));
float wind = item["wind_speed"] | NAN;
hour.wind = std::isnan(wind) ? NO_VALUE : uint8_t(std::max(0L, std::min(254L, lroundf(wind))));
float pop = item["precipitation_probability"] | NAN;
hour.pop = std::isnan(pop) ? NO_VALUE : uint8_t(std::max(0L, std::min(100L, lroundf(pop))));
}
out.fetched_at = now;
fc = out;
return true;
}
inline bool load(esphome::i2c::I2CBus *bus, Forecast &fc) {
uint8_t buf[MAX_SIZE];
const uint8_t start = 0;
fc.count = 0;
if (bus->write_readv(EEPROM_ADDR, &start, 1, buf, sizeof(buf)) != esphome::i2c::ERROR_OK)
return false;
if (buf[0] != MAGIC || buf[1] != VERSION)
return false;
memcpy(&fc.fetched_at, buf + 2, 4);
memcpy(&fc.first_ts, buf + 6, 4);
fc.count = std::min(buf[10], MAX_HOURS);
memcpy(fc.hours, buf + HEADER, fc.count * sizeof(Hour));
return true;
}
inline bool save(esphome::i2c::I2CBus *bus, const Forecast &fc) {
uint8_t buf[MAX_SIZE];
buf[0] = MAGIC;
buf[1] = VERSION;
memcpy(buf + 2, &fc.fetched_at, 4);
memcpy(buf + 6, &fc.first_ts, 4);
buf[10] = fc.count;
memcpy(buf + HEADER, fc.hours, fc.count * sizeof(Hour));
const size_t len = HEADER + fc.count * sizeof(Hour);
// page writes must not cross an 8-byte page boundary; 5 ms write cycle per page
for (size_t off = 0; off < len; off += EEPROM_PAGE) {
uint8_t page[EEPROM_PAGE + 1];
const size_t n = std::min<size_t>(EEPROM_PAGE, len - off);
page[0] = uint8_t(off);
memcpy(page + 1, buf + off, n);
if (bus->write(EEPROM_ADDR, page, n + 1) != esphome::i2c::ERROR_OK)
return false;
esphome::delay(6);
}
return true;
}
} // namespace m5paper_weather
+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:
+59 -3
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));
+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
@@ -17,14 +25,7 @@ esp8266:
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
mdns_ipv6: !include common/esp8266_mdns_ipv6.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:
+9 -9
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
@@ -16,15 +24,7 @@ esp8266:
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
mdns_ipv6: !include common/esp8266_mdns_ipv6.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
+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
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:
+16 -15
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,6 +31,8 @@ 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
@@ -25,21 +41,6 @@ packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.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:
actions: actions:
+11
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:
+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)]);
+9 -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,20 +22,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 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:
- platform: gpio - platform: gpio
+9
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,6 +37,8 @@ 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:
+19 -2
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:
@@ -131,10 +148,10 @@ media_player:
buffer_size: 14000 buffer_size: 14000
media_pipeline: media_pipeline:
speaker: media_spk_resampling_input speaker: media_spk_resampling_input
format: NONE format: WAV # no PSRAM: HA transcodes to WAV, decoding MP3/FLAC here runs the heap out
announcement_pipeline: announcement_pipeline:
speaker: announcement_spk_resampling_input speaker: announcement_spk_resampling_input
format: NONE format: WAV # no PSRAM: HA transcodes to WAV, decoding MP3/FLAC here runs the heap out
rtttl: rtttl:
id: my_rtttl id: my_rtttl
+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 -17
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
+28 -62
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,72 +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 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
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:
- platform: ds248x
ds248x_id: ds2484_module
id: one_wire_bus id: one_wire_bus
platform: ds2482
active_pullup: true
pca9554: pca9554:
- id: pca9554_module - id: pca9554_module
@@ -127,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
+18 -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,26 +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 ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
# PINOUTS: M5ATOM
# IR G12
# NEO G27
# BUTTON G39
# I2C0 SDA G26 white
# I2C0 SCL G32
# I2C1 SDA G25 red
# I2C1 SCL G21
# UART0 RX G3
# UART0 TX G1
# RS485 RX G33
# RS485 TX G23
# RELAY-1 G22
# RELAY-2 G19
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
+29 -52
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,41 +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 ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
# PINOUTS: M5ATOM
# IR G12
# NEO G27
# BUTTON G39
# I2C0 SDA G26
# I2C0 SCL G32
# I2C1 SDA G25
# I2C1 SCL G21
# UART0 RX G3
# UART0 TX G1
# UART1 RX G23
# UART1 TX G33
# 1-WIRE G22
# NC G19
#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
@@ -164,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:
- platform: ds248x
ds248x_id: ds2482_module
id: one_wire_bus id: one_wire_bus
# i2c_id: i2c_main
platform: ds2482
active_pullup: true
modbus: modbus:
uart_id: uart_modbus uart_id: uart_modbus
+22 -17
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,29 +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 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
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:
+49 -18
View File
@@ -1,4 +1,51 @@
--- ---
# 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: substitutions:
device: lvgl-4848s040 device: lvgl-4848s040
name: LVGL 4848S040 name: LVGL 4848S040
@@ -19,6 +66,8 @@ esp32:
variant: esp32s3 variant: esp32s3
flash_size: 16MB flash_size: 16MB
framework: framework:
advanced:
flash_chip: boya
type: esp-idf type: esp-idf
# PSRAM bandwidth for the RGB panel (not set by ESPHome); without it the # PSRAM bandwidth for the RGB panel (not set by ESPHome); without it the
# image shifts during flash/WiFi activity # image shifts during flash/WiFi activity
@@ -35,24 +84,6 @@ packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml ipv6_only: !include common/ipv6_only.yaml
# PINOUTS: Guition ESP32-S3-4848S040, 4", 480x480, ST7701S, capacitive
## 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
api: api:
# status page until Home Assistant connects (log viewers don't subscribe to states) # status page until Home Assistant connects (log viewers don't subscribe to states)
on_client_connected: on_client_connected:
+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:
+17
View File
@@ -1,4 +1,19 @@
--- ---
# 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
@@ -22,6 +37,8 @@ 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:
+67 -38
View File
@@ -1,42 +1,6 @@
--- ---
substitutions: # Hardware: Sunton ESP32-8048S043 (CYD 4.3", 800x480, capacitive touch)
device: lvgl # Pinout:
name: LVGL
area: DEV
comment: LVGL
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
toolchain: esp-idf
framework:
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
# PINOUTS: ESP32 Cheap Yellow Display, 4.3", IPS, Capacitive
# # Display # # Display
# R0 GND # R0 GND
# R1 GND # R1 GND
@@ -92,6 +56,71 @@ packages:
# 2 18 # 2 18
# 3 19 TP_SDA # 3 19 TP_SDA
# 4 20 TP_SCL # 4 20 TP_SCL
# Used:
# GPIO1 main_display (display mipi_rgb data_pins.blue)
# GPIO2 gpio_backlight_pwm (output ledc)
# GPIO3 main_display (display mipi_rgb data_pins.blue)
# GPIO4 main_display (display mipi_rgb data_pins.green)
# GPIO5 main_display (display mipi_rgb data_pins.green)
# GPIO6 main_display (display mipi_rgb data_pins.green)
# GPIO7 main_display (display mipi_rgb data_pins.green)
# GPIO8 main_display (display mipi_rgb data_pins.blue)
# GPIO9 main_display (display mipi_rgb data_pins.blue)
# GPIO14 main_display (display mipi_rgb data_pins.red)
# GPIO15 main_display (display mipi_rgb data_pins.green)
# GPIO16 main_display (display mipi_rgb data_pins.green)
# GPIO19 i2c_main (i2c sda)
# GPIO20 i2c_main (i2c scl)
# GPIO21 main_display (display mipi_rgb data_pins.red)
# GPIO38 main_touch (touchscreen gt911 reset_pin)
# GPIO39 main_display (display mipi_rgb hsync_pin)
# GPIO40 main_display (display mipi_rgb de_pin)
# GPIO41 main_display (display mipi_rgb vsync_pin)
# GPIO42 main_display (display mipi_rgb pclk_pin)
# GPIO45 main_display (display mipi_rgb data_pins.red)
# GPIO46 main_display (display mipi_rgb data_pins.blue)
# GPIO47 main_display (display mipi_rgb data_pins.red)
# GPIO48 main_display (display mipi_rgb data_pins.red)
# I2C:
# 0x5D main_touch (touchscreen gt911)
substitutions:
device: lvgl
name: LVGL
area: DEV
comment: LVGL
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
toolchain: esp-idf
framework:
advanced:
flash_chip: gd
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: api:
# status page until Home Assistant connects (log viewers don't subscribe to states) # status page until Home Assistant connects (log viewers don't subscribe to states)
+201 -165
View File
@@ -1,16 +1,42 @@
--- ---
# 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
weather_entity: weather.openweathermap waste_calendar: calendar.https_www_hviezdoslavov_sk_kalendar_icalfeed_category_0_ongoing_1
# contacts + manual
birthday_calendars: calendar.birthdays, calendar.narodeniny
# Power modes # Power modes
# - USB: always on, WiFi + API, forecast refreshed every hour and redrawn every 15 min # - USB: always on, WiFi + API, events refreshed and redrawn after midnight
# - battery: RTC wakes the board every 15 min (off 1:00-5:00), it draws the forecast # - battery: RTC wakes the board at 00:05, it refreshes the events, draws them and powers
# from EEPROM and powers itself off; WiFi only to refresh the forecast every 6 h # itself off; the RTC timer lasts at most 255 min, so the wake-ups on the way to
# Screens: status (after power-on, until Home Assistant connects) and forecast # 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. # The mode is detected by trying to power off: on USB the board keeps running.
esphome: esphome:
@@ -19,7 +45,7 @@ esphome:
area: ${area} area: ${area}
comment: ${comment} comment: ${comment}
includes: includes:
- include/m5paper_weather.h - include/m5paper_calendar.h
on_boot: on_boot:
- priority: 600 - priority: 600
then: then:
@@ -33,8 +59,8 @@ esphome:
const uint8_t clear[2] = {reg, uint8_t(status & ~0x05)}; const uint8_t clear[2] = {reg, uint8_t(status & ~0x05)};
id(i2c_main)->write(0x51, clear, 2); id(i2c_main)->write(0x51, clear, 2);
} }
m5paper_weather::load(id(i2c_main), m5paper_weather::forecast()); m5paper_calendar::load(m5paper_calendar::events());
ESP_LOGI("m5paper", "Wake-up: %s, forecast: %u h", id(rtc_wake) ? "RTC" : "power-on", m5paper_weather::forecast().count); ESP_LOGI("m5paper", "Wake-up: %s, events: %u", id(rtc_wake) ? "RTC" : "power-on", m5paper_calendar::events().count);
- priority: -100 - priority: -100
then: then:
- if: - if:
@@ -65,6 +91,7 @@ psram:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
globals: globals:
- id: show_status - id: show_status
@@ -76,8 +103,8 @@ globals:
- id: rtc_wake - id: rtc_wake
type: bool type: bool
initial_value: 'false' initial_value: 'false'
# battery cycle running: forecast screen regardless of the connection state # battery cycle running: calendar screen regardless of the connection state
- id: weather_page - id: calendar_page
type: bool type: bool
initial_value: 'false' initial_value: 'false'
- id: fetch_done - id: fetch_done
@@ -92,7 +119,7 @@ wifi:
on_connect: on_connect:
- if: - if:
condition: condition:
lambda: return id(show_status) && !id(weather_page); lambda: return id(show_status) && !id(calendar_page);
then: then:
- component.update: m5paper_display - component.update: m5paper_display
@@ -108,21 +135,18 @@ api:
- lambda: id(show_status) = false; - lambda: id(show_status) = false;
- if: - if:
condition: condition:
lambda: return !id(weather_page); lambda: return !id(calendar_page);
then: then:
- component.update: m5paper_display - component.update: m5paper_display
# outside the battery cycle: refresh a forecast older than an hour # outside the battery cycle (power button, USB) WiFi is up anyway: always refresh
- if: - if:
condition: condition:
and: and:
- lambda: |- - lambda: return !id(calendar_page);
const auto &fc = m5paper_weather::forecast();
const auto now = id(rtc_time).now();
return !id(weather_page) && (!fc.valid() || !now.is_valid() || now.timestamp - fc.fetched_at >= 3600);
- api.connected: - api.connected:
state_subscription_only: true state_subscription_only: true
then: then:
- script.execute: fetch_forecast - script.execute: fetch_events
on_client_disconnected: on_client_disconnected:
- if: - if:
condition: condition:
@@ -133,13 +157,13 @@ api:
- lambda: id(show_status) = true; - lambda: id(show_status) = true;
- if: - if:
condition: condition:
lambda: return !id(weather_page); lambda: return !id(calendar_page);
then: then:
- component.update: m5paper_display - component.update: m5paper_display
# I2C devices (i2c_main) # I2C devices (i2c_main)
# 0x44 SHT30 # 0x44 SHT30
# 0x50 FM24C02 EEPROM (forecast storage, see include/m5paper_weather.h) # 0x50 FM24C02 EEPROM (unused)
# 0x51 BM8563 RTC # 0x51 BM8563 RTC
# 0x5D GT911 touch (docs say 0x14; the driver tries 0x5D, then 0x14) # 0x5D GT911 touch (docs say 0x14; the driver tries 0x5D, then 0x14)
@@ -185,21 +209,27 @@ switch:
internal: true internal: true
script: script:
# One wake-up on battery: refresh the forecast if it is old, draw it, power off # One wake-up on battery: refresh the events if they are old, draw them, power off
- id: battery_cycle - id: battery_cycle
mode: single mode: single
then: then:
- lambda: id(weather_page) = true; - lambda: id(calendar_page) = true;
- wait_until: - wait_until:
condition: condition:
lambda: return id(rtc_time).now().is_valid(); lambda: return id(rtc_time).now().is_valid();
timeout: 10s timeout: 10s
- if: - if:
# RTC wake-up on the way to midnight: nothing to draw
condition: condition:
lambda: |- lambda: |-
const auto &fc = m5paper_weather::forecast();
const auto now = id(rtc_time).now(); const auto now = id(rtc_time).now();
return !fc.valid() || !now.is_valid() || now.timestamp - fc.fetched_at >= 6 * 3600 - 600; 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: then:
- wifi.enable: - wifi.enable:
- wait_until: - wait_until:
@@ -212,49 +242,47 @@ script:
api.connected: api.connected:
state_subscription_only: true state_subscription_only: true
then: then:
- script.execute: fetch_forecast - script.execute: fetch_events
- wait_until: - wait_until:
condition: condition:
lambda: return id(fetch_done); lambda: return id(fetch_done);
timeout: 15s timeout: 15s
- wait_until:
condition:
lambda: return !std::isnan(id(current_temperature).state);
timeout: 5s
- component.update: m5paper_display - component.update: m5paper_display
# let the e-paper refresh finish before cutting power # let the e-paper refresh finish before cutting power
- delay: 4s - delay: 4s
- script.execute: try_sleep - script.execute: try_sleep
- id: fetch_forecast # today and the next 31 days (the month grid and the list)
- id: fetch_events
mode: single mode: single
then: then:
- lambda: id(fetch_done) = false; - lambda: id(fetch_done) = false;
- homeassistant.action: - homeassistant.action:
action: weather.get_forecasts action: calendar.get_events
data: data:
entity_id: ${weather_entity} entity_id: ${waste_calendar}, ${birthday_calendars}
type: hourly start_date_time: !lambda return id(rtc_time).now().strftime("%Y-%m-%d 00:00:00");
duration: "744:00:00"
capture_response: true capture_response: true
on_success: on_success:
- lambda: |- - lambda: |-
auto &fc = m5paper_weather::forecast(); auto &ev = m5paper_calendar::events();
if (m5paper_weather::parse(response, "${weather_entity}", id(rtc_time).now().timestamp, fc)) { if (m5paper_calendar::parse(response, "${waste_calendar}", id(rtc_time).now().timestamp, ev)) {
const bool saved = m5paper_weather::save(id(i2c_main), fc); const bool saved = m5paper_calendar::save(ev);
ESP_LOGI("m5paper", "Forecast: %u h%s", fc.count, saved ? "" : " (EEPROM write failed)"); ESP_LOGI("m5paper", "Events: %u%s", ev.count, saved ? "" : " (flash write failed)");
} else { } else {
ESP_LOGW("m5paper", "Forecast: unexpected response"); ESP_LOGW("m5paper", "Events: unexpected response");
} }
id(fetch_done) = true; id(fetch_done) = true;
# the battery cycle draws on its own # the battery cycle draws on its own
- if: - if:
condition: condition:
lambda: return !id(weather_page); lambda: return !id(calendar_page);
then: then:
- component.update: m5paper_display - component.update: m5paper_display
on_error: on_error:
- lambda: |- - lambda: |-
ESP_LOGW("m5paper", "Forecast: %s", error.c_str()); ESP_LOGW("m5paper", "Events: %s", error.c_str());
id(fetch_done) = true; id(fetch_done) = true;
# Arm the RTC and cut power; if we are still running afterwards, we are on USB # Arm the RTC and cut power; if we are still running afterwards, we are on USB
@@ -262,22 +290,21 @@ script:
mode: single mode: single
then: then:
- lambda: |- - lambda: |-
// next quarter hour, 1:00-5:00 in one go // next 00:05; the timer lasts at most 255 min, so get there in steps
int duration = 900; const int MAX = 255 * 60;
int duration = MAX;
const auto now = id(rtc_time).now(); const auto now = id(rtc_time).now();
if (now.is_valid()) { if (now.is_valid()) {
const int sod = now.hour * 3600 + now.minute * 60 + now.second; const int sod = now.hour * 3600 + now.minute * 60 + now.second;
int next = (sod / 900 + 1) * 900; int left = (86400 + 300 - sod) % 86400;
if (next - sod < 90) // the 1/60 Hz RTC timer may wake us up to a minute early if (left < 600) // just drawn: the 1/60 Hz RTC timer may wake us up to a minute early
next += 900; left += 86400;
const int next_hour = (next / 3600) % 24; // leave at least 20 min for the last step, so it cannot fall into the case above
if (next_hour >= 1 && next_hour < 5) duration = left > MAX ? std::min(MAX, left - 1200) : left;
next = (next / 86400) * 86400 + 5 * 3600;
duration = next - sod;
} }
if (duration > 255) // longer timers count whole minutes if (duration > 255) // longer timers count whole minutes
duration = (duration + 59) / 60 * 60; duration = (duration + 59) / 60 * 60;
id(sleep_s) = std::min(duration, 255 * 60); id(sleep_s) = std::min(duration, MAX);
ESP_LOGI("m5paper", "Powering off for %d s", id(sleep_s)); ESP_LOGI("m5paper", "Powering off for %d s", id(sleep_s));
- bm8563.start_timer: - bm8563.start_timer:
duration: !lambda return id(sleep_s); duration: !lambda return id(sleep_s);
@@ -292,7 +319,8 @@ script:
- lambda: |- - lambda: |-
ESP_LOGI("m5paper", "Still running, USB power"); ESP_LOGI("m5paper", "Still running, USB power");
id(usb_mode) = true; id(usb_mode) = true;
id(weather_page) = false; id(rtc_wake) = false;
id(calendar_page) = false;
id(show_status) = !api::global_api_server->is_connected_with_state_subscription(); id(show_status) = !api::global_api_server->is_connected_with_state_subscription();
- wifi.enable: - wifi.enable:
- component.update: m5paper_display - component.update: m5paper_display
@@ -321,21 +349,24 @@ time:
- bm8563.write_time - bm8563.write_time
- if: - if:
condition: condition:
lambda: return !id(weather_page); lambda: return !id(calendar_page);
then: then:
- component.update: m5paper_display - component.update: m5paper_display
on_time: on_time:
# new day
- seconds: 0 - seconds: 0
minutes: /15 minutes: 0
hours: 0
then: then:
- if: - if:
condition: condition:
lambda: return !id(show_status) && !id(weather_page); lambda: return !id(show_status) && !id(calendar_page);
then: then:
- component.update: m5paper_display - component.update: m5paper_display
# USB mode: keep the stored forecast fresh for battery mode # USB mode: keep the stored events fresh for battery mode
- seconds: 0 - seconds: 0
minutes: 5 minutes: 5
hours: 0
then: then:
- if: - if:
condition: condition:
@@ -344,7 +375,7 @@ time:
- api.connected: - api.connected:
state_subscription_only: true state_subscription_only: true
then: then:
- script.execute: fetch_forecast - script.execute: fetch_events
- platform: bm8563 - platform: bm8563
id: rtc_time id: rtc_time
@@ -388,10 +419,10 @@ button:
on_press: on_press:
- component.update: m5paper_display - component.update: m5paper_display
- platform: template - platform: template
name: Refresh Forecast name: Refresh Calendar
entity_category: config entity_category: config
on_press: on_press:
- script.execute: fetch_forecast - script.execute: fetch_events
sensor: sensor:
- platform: sht3xd - platform: sht3xd
@@ -429,8 +460,7 @@ sensor:
max_value: 100 max_value: 100
.image_defaults: .image_defaults:
icon_large: &icon_large {platform: file, type: BINARY, transparency: chroma_key, resize: 150x150} icon: &icon {platform: file, type: BINARY, transparency: chroma_key}
icon_small: &icon_small {platform: file, type: BINARY, transparency: chroma_key, resize: 44x44}
image: image:
- platform: file - platform: file
@@ -439,37 +469,11 @@ image:
resize: 460x136 resize: 460x136
type: GRAYSCALE type: GRAYSCALE
transparency: alpha_channel transparency: alpha_channel
# weather icons, same order as m5paper_weather::CONDITIONS # same order as m5paper_calendar::Kind
- {<<: *icon_large, file: "mdi:weather-night", id: wl_clear_night} - {<<: *icon, file: "mdi:cake-variant", id: icon_birthday, resize: 32x32}
- {<<: *icon_large, file: "mdi:weather-cloudy", id: wl_cloudy} - {<<: *icon, file: "mdi:trash-can", id: icon_waste, resize: 32x32}
- {<<: *icon_large, file: "mdi:alert-circle-outline", id: wl_exceptional} - {<<: *icon, file: "mdi:cake-variant", id: mark_birthday, resize: 18x18}
- {<<: *icon_large, file: "mdi:weather-fog", id: wl_fog} - {<<: *icon, file: "mdi:trash-can", id: mark_waste, resize: 18x18}
- {<<: *icon_large, file: "mdi:weather-hail", id: wl_hail}
- {<<: *icon_large, file: "mdi:weather-lightning", id: wl_lightning}
- {<<: *icon_large, file: "mdi:weather-lightning-rainy", id: wl_lightning_rainy}
- {<<: *icon_large, file: "mdi:weather-partly-cloudy", id: wl_partlycloudy}
- {<<: *icon_large, file: "mdi:weather-pouring", id: wl_pouring}
- {<<: *icon_large, file: "mdi:weather-rainy", id: wl_rainy}
- {<<: *icon_large, file: "mdi:weather-snowy", id: wl_snowy}
- {<<: *icon_large, file: "mdi:weather-snowy-rainy", id: wl_snowy_rainy}
- {<<: *icon_large, file: "mdi:weather-sunny", id: wl_sunny}
- {<<: *icon_large, file: "mdi:weather-windy", id: wl_windy}
- {<<: *icon_large, file: "mdi:weather-windy-variant", id: wl_windy_variant}
- {<<: *icon_small, file: "mdi:weather-night", id: ws_clear_night}
- {<<: *icon_small, file: "mdi:weather-cloudy", id: ws_cloudy}
- {<<: *icon_small, file: "mdi:alert-circle-outline", id: ws_exceptional}
- {<<: *icon_small, file: "mdi:weather-fog", id: ws_fog}
- {<<: *icon_small, file: "mdi:weather-hail", id: ws_hail}
- {<<: *icon_small, file: "mdi:weather-lightning", id: ws_lightning}
- {<<: *icon_small, file: "mdi:weather-lightning-rainy", id: ws_lightning_rainy}
- {<<: *icon_small, file: "mdi:weather-partly-cloudy", id: ws_partlycloudy}
- {<<: *icon_small, file: "mdi:weather-pouring", id: ws_pouring}
- {<<: *icon_small, file: "mdi:weather-rainy", id: ws_rainy}
- {<<: *icon_small, file: "mdi:weather-snowy", id: ws_snowy}
- {<<: *icon_small, file: "mdi:weather-snowy-rainy", id: ws_snowy_rainy}
- {<<: *icon_small, file: "mdi:weather-sunny", id: ws_sunny}
- {<<: *icon_small, file: "mdi:weather-windy", id: ws_windy}
- {<<: *icon_small, file: "mdi:weather-windy-variant", id: ws_windy_variant}
font: font:
- file: "gfonts://Roboto" - file: "gfonts://Roboto"
@@ -486,22 +490,14 @@ font:
glyphs: *sk_glyphs glyphs: *sk_glyphs
glyphsets: [GF_Latin_Kernel] glyphsets: [GF_Latin_Kernel]
- file: "gfonts://Roboto" - file: "gfonts://Roboto"
id: font_tiny id: font_footer
size: 18 size: 18
glyphs: "0123456789% " glyphs: "0123456789abcdef:. "
- file: "gfonts://Roboto@500" - file: "gfonts://Roboto@500"
id: font_date id: font_date
size: 34 size: 34
glyphs: *sk_glyphs glyphs: *sk_glyphs
glyphsets: [GF_Latin_Kernel] glyphsets: [GF_Latin_Kernel]
- file: "gfonts://Roboto@500"
id: font_hour
size: 28
glyphs: "0123456789-°"
- file: "gfonts://Roboto"
id: font_temp
size: 110
glyphs: "0123456789.,-°C "
color: color:
- id: ink - id: ink
@@ -528,11 +524,9 @@ display:
const int w = it.get_width(); const int w = it.get_width();
const int cx = w / 2; const int cx = w / 2;
const float batt = id(battery_level).state; const float batt = id(battery_level).state;
const float temp = id(current_temperature).state;
const float hum = id(current_humidity).state;
// status screen after power-on, until Home Assistant connects // status screen after power-on, until Home Assistant connects
if (id(show_status) && !id(weather_page)) { if (id(show_status) && !id(calendar_page)) {
it.image(cx, 200, id(esphome_logo), ImageAlign::CENTER); it.image(cx, 200, id(esphome_logo), ImageAlign::CENTER);
it.print(cx, 320, id(font_title), id(ink), TextAlign::CENTER, "${name}"); it.print(cx, 320, id(font_title), id(ink), TextAlign::CENTER, "${name}");
@@ -561,83 +555,125 @@ display:
api_ok ? "Home Assistant: connected" : "Home Assistant: waiting..."); api_ok ? "Home Assistant: connected" : "Home Assistant: waiting...");
if (!std::isnan(batt)) 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, 670, id(font_status), id(ink), "Battery: %.0f%% (%.2f V)", batt, id(battery_voltage).state);
it.printf(40, 720, id(font_status), id(ink), "Forecast: %u h stored", m5paper_weather::forecast().count); 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); it.printf(40, 900, id(font_small), id(ink), "ESPHome %s", ESPHOME_VERSION);
return; return;
} }
// forecast screen // calendar screen
using namespace m5paper_weather; using namespace m5paper_calendar;
image::Image *large[] = {id(wl_clear_night), id(wl_cloudy), id(wl_exceptional), id(wl_fog), image::Image *icons[] = {id(icon_birthday), id(icon_waste)};
id(wl_hail), id(wl_lightning), id(wl_lightning_rainy), id(wl_partlycloudy), image::Image *marks[] = {id(mark_birthday), id(mark_waste)};
id(wl_pouring), id(wl_rainy), id(wl_snowy), id(wl_snowy_rainy), static const char *const DAYS[] = {"Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota", "Nedeľa"};
id(wl_sunny), id(wl_windy), id(wl_windy_variant)}; static const char *const DAYS_SHORT[] = {"Po", "Ut", "St", "Št", "Pi", "So", "Ne"};
image::Image *small[] = {id(ws_clear_night), id(ws_cloudy), id(ws_exceptional), id(ws_fog), static const char *const MONTHS[] = {"Január", "Február", "Marec", "Apríl", "Máj", "Jún",
id(ws_hail), id(ws_lightning), id(ws_lightning_rainy), id(ws_partlycloudy), "Júl", "August", "September", "Október", "November", "December"};
id(ws_pouring), id(ws_rainy), id(ws_snowy), id(ws_snowy_rainy),
id(ws_sunny), id(ws_windy), id(ws_windy_variant)};
static const char *const DAYS[] = {"Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota"};
const auto &fc = m5paper_weather::forecast(); const auto &ev = m5paper_calendar::events();
const auto now = id(rtc_time).now(); 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 // header: date, battery
if (now.is_valid()) it.printf(24, 16, id(font_date), id(ink), "%s %d. %d.", DAYS[weekday(today)], now.day_of_month, now.month);
it.printf(24, 16, id(font_date), id(ink), "%s %d. %d.", DAYS[(now.day_of_week + 6) % 7], now.day_of_month,
now.month);
if (!std::isnan(batt)) if (!std::isnan(batt))
it.printf(w - 24, 22, id(font_small), id(ink), TextAlign::TOP_RIGHT, "%.0f %%", batt); it.printf(w - 24, 22, id(font_small), id(ink), TextAlign::TOP_RIGHT, "%.0f %%", batt);
const Hour *cur = now.is_valid() ? fc.at(now.timestamp) : nullptr; // month grid; days with events get the icons of their kinds
if (cur == nullptr) { const int32_t first = days_from_civil(now.year, now.month, 1);
it.print(cx, 230, id(font_status), id(ink), TextAlign::CENTER, "Predpoveď nie je k dispozícii"); const int32_t next = now.month == 12 ? days_from_civil(now.year + 1, 1, 1) : days_from_civil(now.year, now.month + 1, 1);
} else { const int dim = next - first, lead = weekday(first);
// current hour uint8_t kinds[32] = {};
if (cur->cond < NUM_CONDITIONS) for (int i = 0; i < ev.count; i++) {
it.image(24, 80, large[cur->cond], id(ink)); if (ev.items[i].day >= first && ev.items[i].day < next)
if (cur->temp2 != NO_TEMP) kinds[ev.items[i].day - first + 1] |= 1 << ev.items[i].kind;
it.printf(200, 70, id(font_temp), id(ink), "%.0f°", cur->temp2 / 2.0f); }
it.print(204, 200, id(font_status), id(ink), condition_name(cur->cond)); const int col_w = 70, row_h = 54, gx = (w - 7 * col_w) / 2, gy = 150;
if (cur->wind != NO_VALUE) it.printf(cx, 70, id(font_status), id(ink), TextAlign::TOP_CENTER, "%s %d", MONTHS[now.month - 1], now.year);
it.printf(204, 245, id(font_small), id(ink), "vietor %u km/h", cur->wind); for (int c = 0; c < 7; c++)
if (cur->pop != NO_VALUE) it.print(gx + c * col_w + col_w / 2, 116, id(font_small), id(ink), TextAlign::TOP_CENTER, DAYS_SHORT[c]);
it.printf(204, 280, id(font_small), id(ink), "zrážky %u %%", cur->pop); 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 24 hours: 3 columns x 8 rows // next 14 days; waste collection today or tomorrow is inverted: put the bin out
const uint32_t first = (now.timestamp / 3600 + 1) * 3600; const int top = 490, list_h = 50, max_rows = 8;
const int top = 440, row_h = 60, col_w = w / 3; it.horizontal_line(24, top - 12, w - 48, id(ink));
for (int i = 0; i < 24; i++) { int rows = 0, more = 0;
const Hour *h = fc.at(first + i * 3600); for (int i = 0; i < ev.count; i++) {
if (h == nullptr) 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; break;
const int x = (i / 8) * col_w + 12;
const int y = top + (i % 8) * row_h;
const auto t = ESPTime::from_epoch_local(first + i * 3600);
it.printf(x, y + 14, id(font_hour), id(ink), "%02d", t.hour);
if (h->cond < NUM_CONDITIONS)
it.image(x + 42, y + 8, small[h->cond], id(ink));
if (h->temp2 != NO_TEMP)
it.printf(x + 94, y + 6, id(font_hour), id(ink), "%.0f°", h->temp2 / 2.0f);
if (h->pop != NO_VALUE && h->pop >= 10)
it.printf(x + 94, y + 38, id(font_tiny), id(ink), "%u %%", h->pop);
} }
for (int c = 1; c < 3; c++)
it.vertical_line(c * col_w, top, 8 * row_h, id(ink));
} }
if (ev.valid()) {
// indoor const auto f = ESPTime::from_epoch_local(ev.fetched_at);
it.horizontal_line(24, 340, w - 48, id(ink)); it.printf(w - 24, 944, id(font_footer), id(ink), TextAlign::BOTTOM_RIGHT, "%d. %d. %02d:%02d", f.day_of_month,
it.printf(cx, 380, id(font_status), id(ink), TextAlign::CENTER, "Doma %.1f °C · %.0f %%", temp, hum); f.month, f.hour, f.minute);
it.horizontal_line(24, 420, w - 48, id(ink));
// footer
if (fc.valid()) {
const auto f = ESPTime::from_epoch_local(fc.fetched_at);
it.printf(24, 944, id(font_small), id(ink), TextAlign::BOTTOM_LEFT, "predpoveď %d. %d. %02d:%02d",
f.day_of_month, f.month, f.hour, f.minute);
} }
if (now.is_valid())
it.printf(w - 24, 944, id(font_small), id(ink), TextAlign::BOTTOM_RIGHT, "%02d:%02d", now.hour, now.minute);
touchscreen: touchscreen:
- platform: gt911 - platform: gt911
+18 -15
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,26 +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 ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
# PINOUTS: M5ATOM
# IR G12
# NEO G27
# BUTTON G39
# I2C0 SDA G26
# I2C0 SCL G32
# I2C1 SDA G25
# I2C1 SCL G21
# UART0 RX G3
# UART0 TX G1
# UART1 RX G23
# UART1 TX G33
# 1-WIRE G22
# NC G19
modbus: modbus:
uart_id: uart_modbus uart_id: uart_modbus
+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}
+22
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
@@ -14,6 +28,7 @@ esphome:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
nspanel: !include nspanel: !include
file: common/nspanel.yaml file: common/nspanel.yaml
vars: vars:
@@ -51,6 +66,13 @@ nspanel_lovelace:
title: Kúrenie title: Kúrenie
thermo_entity_id: climate.bt_trv_bedroom thermo_entity_id: climate.bt_trv_bedroom
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.bedroom_nspanel_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
name: Left Button name: Left Button
+23
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
@@ -60,6 +75,7 @@ external_components:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.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:
@@ -441,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
+22
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
@@ -13,6 +27,7 @@ esphome:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
nspanel: !include nspanel: !include
file: common/nspanel.yaml file: common/nspanel.yaml
vars: vars:
@@ -108,6 +123,13 @@ nspanel_lovelace:
- name: Auto-zatváranie - name: Auto-zatváranie
entity_id: switch.gate_auto_close entity_id: switch.gate_auto_close
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.fireplace_nspanel_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
name: Left Button name: Left Button
+22
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
@@ -13,6 +27,7 @@ esphome:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
nspanel: !include nspanel: !include
file: common/nspanel.yaml file: common/nspanel.yaml
vars: vars:
@@ -61,6 +76,13 @@ nspanel_lovelace:
- name: Auto-zatváranie - name: Auto-zatváranie
entity_id: switch.gate_auto_close entity_id: switch.gate_auto_close
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.office_j_nspanel_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
name: Left Button name: Left Button
+21
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
@@ -82,6 +96,13 @@ nspanel_lovelace:
- name: Auto-zatváranie - name: Auto-zatváranie
entity_id: switch.gate_auto_close entity_id: switch.gate_auto_close
- type: cardEntities
title: Info
entities:
- name: Zariadenie
entity_id: button.office_r_nspanel_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
name: Left Button name: Left Button
+44 -7
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
@@ -13,6 +27,7 @@ esphome:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml
nspanel: !include nspanel: !include
file: common/nspanel.yaml file: common/nspanel.yaml
vars: vars:
@@ -23,6 +38,7 @@ nspanel_lovelace:
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
@@ -55,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
@@ -137,6 +154,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.patio_nspanel_info
icon: information-outline
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
name: Left Button name: Left Button
@@ -145,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
@@ -156,19 +178,24 @@ 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
- platform: homeassistant
id: patio_status
entity_id: binary_sensor.mcu_patio_status
switch: switch:
- platform: gpio - platform: gpio
name: Outside Light Back name: Outside Light Back
@@ -183,3 +210,13 @@ switch:
entity_category: config entity_category: config
pin: pin:
number: 19 number: 19
script:
# jump straight to the "Von" card (one render instead of home + next + next):
# make it the default page for a moment, render it, restore the home card
- id: show_outside_card
then:
- lambda: |-
id(nspanel_id).set_default_page("card_outside");
id(nspanel_id).render_default_page();
id(nspanel_id).set_default_page("card_home");
+13 -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,19 +29,14 @@ 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 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
name: "MS Teams Presence Light" name: "MS Teams Presence Light"
+20 -15
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,28 +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 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
i2c: i2c:
# - id: i2c0 # - id: i2c0
# sda: 26 # sda: 26
+13 -1
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,6 +30,7 @@ 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
@@ -187,4 +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]
+13
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-washer device: pow-washer
name: Washer POW name: Washer POW
@@ -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
+14
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,11 +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 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
@@ -16,6 +21,7 @@ esp8266:
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
mdns_ipv6: !include common/esp8266_mdns_ipv6.yaml
remote_receiver: remote_receiver:
pin: 4 pin: 4
+285
View File
@@ -0,0 +1,285 @@
---
# 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
id: creality_color
on_value:
- script.execute: show_filament_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
id: openprinttag_color
on_value:
- script.execute: show_filament_color
script:
# The filament color on the filament_color light: the OpenPrintTag's, else the Creality tag's
- id: show_filament_color
then:
- lambda: |-
std::string x = id(openprinttag_color).state;
if (x.size() < 7)
x = id(creality_color).state;
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
+26 -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:
@@ -45,15 +59,6 @@ packages:
# 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
@@ -86,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:
@@ -118,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
@@ -166,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();
@@ -266,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:
@@ -308,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
@@ -328,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
@@ -344,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
+14 -1
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,6 +26,8 @@ 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
@@ -22,6 +35,7 @@ esp32:
packages: packages:
common: !include common/common.yaml common: !include common/common.yaml
ipv6_only: !include common/ipv6_only.yaml ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
i2c: i2c:
sda: 25 sda: 25
@@ -109,4 +123,3 @@ switch:
pin: pin:
number: 19 number: 19
mode: OUTPUT mode: OUTPUT
+12 -12
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
@@ -18,18 +29,7 @@ esp8266:
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
mdns_ipv6: !include common/esp8266_mdns_ipv6.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
+12 -12
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
@@ -18,18 +29,7 @@ esp8266:
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
mdns_ipv6: !include common/esp8266_mdns_ipv6.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
+13 -12
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,23 +30,13 @@ esphome:
friendly_name: ${name} friendly_name: ${name}
area: ${area} area: ${area}
comment: ${comment} comment: ${comment}
esp8266: esp8266:
board: esp01_1m board: esp01_1m
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
mdns_ipv6: !include common/esp8266_mdns_ipv6.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
+44 -1
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
@@ -23,8 +63,11 @@ esphome:
esp32: esp32:
variant: esp32s3 variant: esp32s3
flash_size: 16MB flash_size: 16MB
flash_frequency: 40MHz # the IDF 5.5.5 bootloader reads garbage from this flash (mfr 0x46) at 80MHz
toolchain: esp-idf toolchain: esp-idf
framework: framework:
advanced:
flash_chip: generic
type: esp-idf type: esp-idf
psram: psram:
@@ -41,7 +84,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
+17 -2
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
@@ -16,6 +20,7 @@ esp8266:
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
mdns_ipv6: !include common/esp8266_mdns_ipv6.yaml
# wifi: # wifi:
# use_address: mcu-mini-04.local # use_address: mcu-mini-04.local
@@ -49,8 +54,18 @@ binary_sensor:
entity_id: binary_sensor.zigbee_staircase_pir_occupancy entity_id: binary_sensor.zigbee_staircase_pir_occupancy
on_state: on_state:
if: if:
condition: condition: &no_motion
binary_sensor.is_off: motion and:
- binary_sensor.is_off: motion
- binary_sensor.is_off: motion_2
then:
- light.turn_off: light_relay
- platform: homeassistant
id: motion_2
entity_id: binary_sensor.zigbee_staircase_2_pir_occupancy
on_state:
if:
condition: *no_motion
then: then:
- light.turn_off: light_relay - light.turn_off: light_relay
+234 -125
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,52 +20,134 @@ 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 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: display:
- id: my_green - platform: mipi_spi
hex: 00ff00 id: main_display
- id: my_magenta model: ILI9341
hex: ff00ff cs_pin: 7
- id: my_red dc_pin: 8
hex: ff0000 reset_pin: 10
- id: my_white invert_colors: false
hex: ffffff data_rate: 40MHz
- id: status_ok update_interval: never
hex: 4dd966 auto_clear_enabled: false
- id: status_wait
hex: ffb300 touchscreen:
- id: status_dim - platform: xpt2046
hex: 8c8c8c 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: image:
- platform: file - platform: file
@@ -66,103 +158,120 @@ image:
transparency: alpha_channel transparency: alpha_channel
font: font:
- file: "gfonts://Roboto@500"
id: font_clock
size: 80
glyphs: "0123456789:-"
- file: "gfonts://Roboto" - file: "gfonts://Roboto"
id: font_default id: font_title
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 size: 24
- file: "gfonts://Roboto" - file: "gfonts://Roboto"
id: roboto_16 id: font_status
size: 16 size: 14
- 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
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: "--:--"
display: # 2: status (shown until Home Assistant connects)
- platform: mipi_spi - id: status_page
model: ILI9341 on_load:
cs_pin: 7 - script.execute: update_status
dc_pin: 8 widgets:
reset_pin: 10 - image:
invert_colors: false src: esphome_logo
lambda: |- align: TOP_MID
it.fill(Color::BLACK); y: 8
- label:
// status screen until Home Assistant connects (240x320) align: TOP_MID
if (!api::global_api_server->is_connected_with_state_subscription()) { y: 78
const int cx = it.get_width() / 2; text_font: font_title
it.image(cx, 48, id(esphome_logo), ImageAlign::CENTER); text: "${name}"
it.print(cx, 100, id(roboto_24), id(my_white), TextAlign::CENTER, "${name}"); - obj:
x: 8
int y = 130; y: 116
if (wifi::global_wifi_component->is_connected()) { width: 224
it.printf(8, y, id(roboto_16), id(status_ok), "WiFi: connected (%d dBm)", height: SIZE_CONTENT
wifi::global_wifi_component->wifi_rssi()); bg_opa: TRANSP
y += 22; border_width: 0
// IPv6 first (skip link-local), then IPv4 pad_all: 0
char buf[network::IP_ADDRESS_BUFFER_SIZE]; scrollbar_mode: "OFF"
for (bool v6 : {true, false}) { layout:
for (auto &ip : wifi::global_wifi_component->get_ip_addresses()) { type: flex
if (!ip.is_set() || ip.is_ip6() != v6 || y > 200) flex_flow: column
continue; pad_row: 6
ip.str_to(buf); widgets:
if (v6 && strncmp(buf, "fe80", 4) == 0) - label:
continue; id: status_wifi
it.print(8, y, id(roboto_12), id(status_dim), buf); text_font: font_status
y += 16; text: ""
} - label:
} id: status_ips
} else { text_font: font_status
it.print(8, y, id(roboto_16), id(status_wait), "WiFi: connecting..."); text_color: 0x8C8C8C
y += 22; text: ""
} - label:
y += 8; id: status_ha
it.print(8, y, id(roboto_16), api::global_api_server->is_connected() ? id(status_ok) : id(status_wait), text_font: font_status
api::global_api_server->is_connected() ? "Home Assistant: connected" : "Home Assistant: waiting..."); text: ""
- label:
it.printf(8, it.get_height() - 8, id(roboto_12), id(status_dim), TextAlign::BOTTOM_LEFT, "ESPHome %s", id: status_footer
ESPHOME_VERSION); text_font: font_status
it.printf(it.get_width() - 8, it.get_height() - 8, id(roboto_12), id(status_dim), TextAlign::BOTTOM_RIGHT, text_color: 0x8C8C8C
"up %us", (unsigned) (millis() / 1000)); text: ""
return;
}
it.print(0, 0, id(b612_12), id(my_white), TextAlign::TOP_LEFT, "HELLO WORLD!");
it.print(0, 14, id(b612_12), id(my_green), TextAlign::TOP_LEFT, "HELLO WORLD!");
it.print(0, 28, id(b612_12), id(my_magenta), TextAlign::TOP_LEFT, "HELLO WORLD!");
it.print(0, 42, id(b612_12), id(my_red), TextAlign::TOP_LEFT, "HELLO WORLD!");
+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
@@ -16,16 +34,7 @@ esp8266:
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
mdns_ipv6: !include common/esp8266_mdns_ipv6.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
+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
@@ -16,13 +23,7 @@ esp8266:
packages: packages:
common: !include common/common_esp8266.yaml common: !include common/common_esp8266.yaml
mdns_ipv6: !include common/esp8266_mdns_ipv6.yaml
# Sonoff Basic R2
# GPIO00 - BUTTON
# GPIO12 - RELAY
# GPIO13 - LED1
# GPIO03 - RX PIN
# GPIO01 - TX PIN
binary_sensor: binary_sensor:
- platform: gpio - platform: gpio
+13 -1
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,11 +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 ipv6_only: !include common/ipv6_only.yaml
status_led: !include common/status_led_atom.yaml
api: api:
actions: actions:
@@ -358,4 +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
+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"