Neueste Beiträge

#1
ESP Familie / z2m: ESP32-C6 Zigbee Button Mu...
Letzter Beitrag von TomLee - 17 Juni 2026, 17:03:54
Hi,

getestet mit ESP32-C6 Super Mini, Arduino Framework, Zigbee2MQTT.

#include <Arduino.h>

#ifndef ZIGBEE_MODE_ZCZR
#error "Select Zigbee ZCZR mode in Tools -> Zigbee mode"
#endif

#include "Zigbee.h"

#define BUTTON_PIN BOOT_PIN

#define ACTION_SINGLE 1
#define ACTION_DOUBLE 2
#define ACTION_TRIPLE 3
#define ACTION_HOLD   4

ZigbeeMultistate buttonDevice(1);

bool lastState = HIGH;
uint32_t pressStart = 0;
uint32_t lastRelease = 0;
uint8_t clickCount = 0;
bool holdSent = false;

void sendAction(uint8_t action)
{
    buttonDevice.setMultistateInput(action);
    buttonDevice.reportMultistateInput();
    Serial.printf("Action sent: %u\n", action);
}

void setup()
{
    Serial.begin(115200);
    pinMode(BUTTON_PIN, INPUT_PULLUP);

    // Factory Reset: BOOT-Button beim Start gedrückt halten
    delay(200);
    if (digitalRead(BUTTON_PIN) == LOW) {
        Serial.println("Factory reset triggered!");
        Zigbee.factoryReset();
    }

    buttonDevice.setManufacturerAndModel("Custom", "ESP32-Zigbee-Button");
    buttonDevice.addMultistateInput();
    buttonDevice.setMultistateInputStates(4);

    Zigbee.addEndpoint(&buttonDevice);

    Serial.println("Starting Zigbee...");

    if (!Zigbee.begin(ZIGBEE_ROUTER))
    {
        Serial.println("Zigbee start failed!");
        ESP.restart();
    }

    // Timeout nach 30s – läuft auch ohne Verbindung weiter
    uint32_t timeout = millis();
    while (!Zigbee.connected() && millis() - timeout < 30000)
    {
        Serial.print(".");
        delay(100);
    }

    if (Zigbee.connected()) {
        Serial.println("\nConnected");
    } else {
        Serial.println("\nNot connected, running anyway...");
    }
}

void loop()
{
    bool state = digitalRead(BUTTON_PIN);

    if (state == LOW && lastState == HIGH)
    {
        pressStart = millis();
        holdSent = false;
    }

    if (state == LOW && !holdSent && millis() - pressStart > 1000)
    {
        sendAction(ACTION_HOLD);
        holdSent = true;
        clickCount = 0;
    }

    if (state == HIGH && lastState == LOW)
    {
        if (!holdSent)
        {
            clickCount++;
            lastRelease = millis();
        }
    }

    if (clickCount > 0 && millis() - lastRelease > 500)
    {
        if (clickCount == 1) sendAction(ACTION_SINGLE);
        else if (clickCount == 2) sendAction(ACTION_DOUBLE);
        else sendAction(ACTION_TRIPLE);
        clickCount = 0;
    }

    lastState = state;
    delay(10);
}

Arduino IDE Einstellungen:

  • Board ESP32C6 Dev Module
  • USB CDC On Boot Enabled
  • CPU Frequency 160MHz (WiFi)
  • Core Debug Level None
  • Erase All Flash Before Sketch Upload Enabled
  • Flash Frequency 80MHz
  • Flash Mode QIO
  • Flash Size 4MB (32Mb)
  • JTAG Adapter Disabled
  • Partition SchemeZigbee ZCZR 4MB with spiffs
  • Upload Speed 921600
  • Zigbee ModeZigbee ZCZR (coordinator/router)

Z2M External Converter:
Datei /opt/zigbee2mqtt/data/external_converters/custom_devices.js:

const e = require('zigbee-herdsman-converters/lib/exposes');

const lastSeen = {};

const definition = {
    zigbeeModel: ['ESP32-Zigbee-Button'],
    model: 'ESP32-Zigbee-Button',
    vendor: 'Custom',
    description: 'ESP32-C6 Zigbee Button',
    fromZigbee: [
        {
            cluster: 'genMultistateInput',
            type: ['attributeReport', 'readResponse'],
            convert: (model, msg, publish, options, meta) => {
                const actionMap = {1: 'single', 2: 'double', 3: 'triple', 4: 'hold'};
                const value = msg.data['presentValue'];
                if (!actionMap[value]) return;

                // Duplikat-Filter für Mesh-Routing
                const key = `${meta.device.ieeeAddr}_${value}`;
                const now = Date.now();
                if (lastSeen[key] && now - lastSeen[key] < 1000) return;
                lastSeen[key] = now;

                return {action: actionMap[value]};
            },
        },
    ],
    toZigbee: [],
    exposes: [e.enum('action', e.access.STATE, ['single', 'double', 'triple', 'hold'])
        .withDescription('Button action')],
    configure: async (device, coordinatorEndpoint) => {
        const endpoint = device.getEndpoint(1);
        await endpoint.bind('genMultistateInput', coordinatorEndpoint);
        await endpoint.configureReporting('genMultistateInput', [{
            attribute: 'presentValue',
            minimumReportInterval: 0,
            maximumReportInterval: 0,
            reportableChange: 1,
        }]);
    },
};

module.exports = definition;

z2m Log:[17.6.2026, 16:33:38] z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/0x543204fffe3d996c', payload '{"action":"single","linkquality":183}'

[17.6.2026, 16:33:40] z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/0x543204fffe3d996c', payload '{"action":"double","linkquality":183}'

[17.6.2026, 16:33:42] z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/0x543204fffe3d996c', payload '{"action":"triple","linkquality":122}'

[17.6.2026, 16:33:44] z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/0x543204fffe3d996c', payload '{"action":"hold","linkquality":191}'

Kein Eintrag in configuration.yaml nötig. Z2M lädt alle Dateien aus dem external_converters-Ordner automatisch.



Hinweise:

  • Als Router gedacht (dauerhaft am Strom), erweitert das Zigbee-Mesh
  • Factory Reset: BOOT-Button beim Einschalten gedrückt halten
  • Beim ersten Pairing: in Z2M permit_join aktivieren, dann ESP starten
  • Getestet mit Zigbee2MQTT v2.9.1 / zigbee-herdsman-converters v26.12.0

Hat ne Weile gedauert bis alles lief, aber der Weg war das Ziel. Spaß hats auf jeden Fall gemacht!
Verbesserungsvorschläge, Ideen oder Erweiterungen sind herzlich willkommen.

Gruss Thomas
#2
Wallboxen und E-Fahrzeuge / Aw: Leapmotor integration?
Letzter Beitrag von Stonemuc - 17 Juni 2026, 17:01:01
Wie hast du das mit dem python Schnipsel jetzt gelöst? Ich check nichts...
Kann ich da selbst eine Abfrage für meinen C10 basteln? Per python Scriot auf meinem HomeServer? Das wäre natürlich klasse, wenn du mir da mal sagen könntest wie man das löst...

Ich hab es jetzt vorerst mal so gelöst:

In einem Docker Container Leapconnect von Marko Ceri gestartet und dann per MQTT auf meinen MQTT Broker die Daten gesendet. Die greife ich dann in FHEM per MQTT2DEVICE ab..da könnte man ja auch set Befehle übermitteln...wobei ich es vorerst nicht brauche.

Hier mal der Link zu Leapconnect.
https://github.com/markoceri/leapconnect
#3
Marktplatz - Güter / Aw: [V] Adapterplatine ESP32 D...
Letzter Beitrag von FHEM-User22 - 17 Juni 2026, 16:27:10
Meine auch, Dankeschön
#4
Termine und Veranstaltungen / Aw: Stammtisch Leipzig
Letzter Beitrag von FHEM-User22 - 17 Juni 2026, 16:26:33
Ich freue mich auch.
Bis morgen.

Grüße aus Grimma
#5
Termine und Veranstaltungen / Aw: Stammtisch Leipzig
Letzter Beitrag von DS_Starter - 17 Juni 2026, 16:23:53
Prima :-) ... ich fraue mich darauf!

LG,
Heiko
#6
Marktplatz - Güter / Aw: [V] Adapterplatine ESP32 D...
Letzter Beitrag von frober - 17 Juni 2026, 16:23:04
Meine auch, danke.
#7
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von DS_Starter - 17 Juni 2026, 16:16:47
ZitatWoher die 16500 Wh kommen, ist mir rätselhaft.
Achtung:  Das ist eine Normierungsgrenze für die Erstellung von Trainingsdaten.

Zum Beispiel:
Normierungsgrenzen: PV=7788 Wh, Hausverbrauch: Min=0 Wh / Max=6290 Wh
Dieser Wert wird immer ein wenig höher liegen als das wahrscheinliche Maximum und ist die obere Normgrenze == 1.
Das hat nichts mit einer harten Grenze im Sinne Kappung zu tun.
Diese Grenze ist auch nicht fest, sondern wird bei jedem Trainingslauf aus den AI-Rohdaten gelesen und entsprechend für FANN aufbereitet.

#8
Solaranlagen / Aw: 76_SolarForecast - Informa...
Letzter Beitrag von TheTrumpeter - 17 Juni 2026, 16:12:11
Zitat von: 300P am 16 Juni 2026, 17:08:04et voilà ! ->>> hier ist der Wert -> Grafik
Da steht bei mir 16500 Wh, obwohl ich folgendes definiert habe:
attr mySolarForecast setupInverterDev01 myHuawei etotal=Accumulated_energy_yield:kWh capacity=15000 strings=PV1,PV3 asynchron=1 pvOut=Active_Power:W pvIn=PV_Input_Power:W(Die 16500 Wh sind lustigerweise die theoretische Maximalleistung meines WRs, der allerdings mittels "länderspezifischem Parametersatz" auf 15 kW limitiert ist.)

Weiters habe ich
attr mySolarForecast setupStringPeak PV1=8.46 PV3=8.46Das sind aber 16920 W in Summe.

Woher die 16500 Wh kommen, ist mir rätselhaft. (Die Limitierung vom WR auf die 15 kW funktioniert auch. Wenn die Sonne hinter den Wolken hervorkommt, kommen exakt 15 kW (+/- 2-3W) aus dem WR raus. Ich "sehe" nie Werte größer als 15004 W.)
#9
Sprachsteuerung / Aw: alexa-fhem im Docker und f...
Letzter Beitrag von Hirnlos - 17 Juni 2026, 16:04:07
nach einem Neutstart sind beide Container : healthy
#10
Termine und Veranstaltungen / Aw: Stammtisch Leipzig
Letzter Beitrag von Otto123 - 17 Juni 2026, 15:56:26
Ich hoffe es sind alle wohl auf, 11 Anmeldungen im Planer dazu noch ev. 2 aus dem Ort.
Der Jäger hatte vorgestern Erfolg und hat heute frisch gewurstet.
Ab 17:00 Uhr brennt wie immer der Grill an der Mühle und für Getränke sorge ich.

Gruß Otto