Automatyzacja Termostatów

to wiem ale jak to w funkcji uwzględnić żeby sprawdzała
1 status Klimy
2 histerezę
3 jaka jest temperatura zadana
4 nie wysyłała niepotrzebnie komend jeżeli nie zmieniła się zadana wyjściowa, ponieważ aktualnie mimo że klima jest wyłączona i zadana temperatura się nie zmieniła to wysyła payload wraz ze zmianą temperatury

5.12.2025, 08:21:56node: Funkcja Salon Wyjście
zigbee2mqtt/Temperatura Salon : msg.payload : Object
{ klima: "OFF", occupied_heating_setpoint: 20 }
5.12.2025, 08:21:56node: Switch Klima Wyłącz
zigbee2mqtt/Temperatura Salon : msg.payload : Object
{ klima: "OFF", occupied_heating_setpoint: 20 }
5.12.2025, 08:21:56node: Klima Wyłącz
zigbee2mqtt/Temperatura Salon : msg.payload : Object
{ klima: "OFF", occupied_heating_setpoint: 20 }

Próbowałem to zrobić to mi się cały node red posypał więc na te chwile to funkcjonuje w ten sposób
Funkcja Salon

let vt1 = flow.get('Zadana') || 22; // temperatura zadana
let vt2 = parseFloat(msg.payload);  // temperatura aktualna

let lastState = flow.get('lastState') || "OFF"; // poprzedni stan: ON/OFF
let hysteresis = 0.5; // szerokość tolerancji

let klimaState;

// Logika z histerezą
if (lastState === "OFF" && vt2 < (vt1 - hysteresis)) {
    klimaState = "ON";
}

else if (lastState === "ON" && vt2 > (vt1 + hysteresis)) {
    klimaState = "OFF";
}

else {
    klimaState = lastState; // stan nie zmienia się
}

// Zapisujemy
flow.set('lastState', klimaState);

// Ustal temperaturę docelową
let newTemp = (klimaState === "ON") ? 30 : vt1;

// Przygotowanie wiadomości
msg.payload = {
    klima: klimaState,
    occupied_heating_setpoint: newTemp
};

return msg;

Funkcja inny pokój, bez klimy

let vt1 = flow.get('Zadanapawel') || 22; // temperatura zadana dla Pawła
let vt2 = parseFloat(msg.payload);        // temperatura aktualna

let lastState = flow.get('lastState') || "OFF"; // poprzedni stan: ON/OFF
let hysteresis = 0.5; // szerokość tolerancji

let headState;

// Logika z histerezą dla głowicy
if (lastState === "OFF" && vt2 < (vt1 - hysteresis)) {
    headState = "ON";
} else if (lastState === "ON" && vt2 > (vt1 + hysteresis)) {
    headState = "OFF";
} else {
    headState = lastState; // stan nie zmienia się
}

// Zapisujemy stan głowicy
flow.set('lastState', headState);

// Przygotowanie wiadomości dla głowicy z temperaturą zadaną
msg.payload = {
    occupied_heating_setpoint: vt1
};

return msg;

Jakoś to działa ale myśle że niepotrzebnie obciążam całość niepotrzebnie wysyłanymi payload skoro ani zadana, ani potrzeba on/off klimy się nie zmienia wiem że trzeba dać return null tylko pytanie gdzie

Jak nie potrafisz pisać funkcji, masz do dyspozycji podstawowe nody jak switch, change , które pozwalają realizować nawet zawansowane filtrowanie procesu.
Poniżej masz przykład gdzie sprawdzam status klimy i poziom wentyla i od tych statusów wybieram ścieżkę.


W nodzie funkcji też możesz ustawić kilka wyjść i na podstawie analizowanych danych wybrać którym wyjściem proces pójdzie dalej.
Przykład gdzie jednym wyjściem puszczam proces tylko w lato

var a = flow.get('pora-rok');


if ((a == "winter") || (a == "autumn") || (a == "spring")){
    msg.payload = "on"
    return [msg, null]
}
if (a == "summer") {
    msg.payload = "off"
    return [null, msg]
}

A czemu z uporem maniaka sterujesz godzinowo a nie swoją obecnością ? Zbieranie temperatury z jednego czujnika jest błędem bo jak padnie CI czujnik – to Twój system będzie działał na ostatniej znanej temperaturze, co w praktyce oznacza: albo grzanie do oporu, albo niegrzanie wcale. Zero bezpieczeństwa, zero logiki, zero kontroli.

spokojnie nadal się uczę, jestem bardziej hobbystom niż profesjonalistą. Jestem zawsze wdzięczny za każdą pomoc.

Nie rozmyślałem na takim rozwiązaniem, rozumiem że musiałbym doposażyć się w czujniki obecności, mógłbyś naświetlić temat ?

Obecność czyli kiedy HA “wie” że jesteś w domu ( Ty i/lub domownicy) i wtedy taka automatyzacja ma sens ( bo nie będziesz grzał przecież pustej chaty a jedynie utrzymywał minimalną temperaturę).
Ha dostaje info o tym przez twój telefon czyli geolokalizacja ( tzw strefa domowa zdefiniowana w GUI HA ) oraz inne urządzenia przez które Ha może w 100 % stwierdzić że jesteś fizycznie w domu czyli zalogowanie się do sieci WIFI , beacony etc… Nie jest to czujnik ruchu bo czujnik nie wykrywa konkretnej osoby a ruch.

Nie znam fizyki Twojego mieszkania czy domu.

Ja mam małe mieszkanie w bloku ale u siebie rozwiązałem to poprzez odczyt z 3 czujników plus powiązanie z temperaturą na zewnątrz.
I Ha dopiero wtedy grzeje kiedy :

  1. jestem w domu,
  2. średnia temperatura jest <21 stopni i utrzymuje się przez minimum 15 minut a temp zewnętrzna < od 6 stopni,
  3. Wtedy HA otwiera zawory na kaloryferach i czeka do tem 22.5 ( to jest mój maks ) , po osiągnieciu zadanej temperatury zawory są zakręcane.

To jest przykład.

No ale musiałbym umożliwić wysyłanie danych z telefonu do HA, a tego chce uniknąć bo telefon to jednak przedmiot ściśle osobisty.

Albo rybka albo akwarium. Więc pozostaje Ci badanie obecności poprzez BLE i WIFI.
Home Assistant nie ma dostępu do TWOICH danych. Ma dostęp tylko do tych, które mu SAM dasz. Presence to tylko informacja ‘jestem w domu / nie ma mnie’, nic więcej.
A jeżeli upierasz się sterować godzinowo to nie możesz tego podpierać tylko na jednym czujniku i to bateryjnym.

To nazywasz komfortem termicznym ? Ponad 2 st różnicy między grzej/stop, moja żona by mnie pogoniła z taką automatyzacją.
Obecność jak najbardzeij ok, ale jako jeden z dodatkowych warunków , a nie wykładnia grzej lub nie :slight_smile:

Okey Funkcja z filtrem, dla osób które mogą chcieć takiego rozwiązania jak i również dla tych które pomogą w rozwoju tego rozwiązania coś poprawią wychwycą błędy.
Wyjście na Głowice i Klimatyzator i nie spamuje node red jeżeli stan się nie zmienia nie wysyła nic (testuje) :

// Pobranie temperatur
const vt1 = parseFloat(flow.get('Zadanapawel')) || 22; // temperatura zadana
const vt2 = parseFloat(msg.payload);                   // temperatura aktualna

// Jeśli nie ma temperatury aktualnej → nie robimy nic
if (isNaN(vt2)) {
    node.warn("Brak poprawnej temperatury aktualnej (msg.payload)");
    return null;
}

// Klucze pamięci — unikalne dla głowicy Pawła
const stateKey = 'lastState_pawel';

// Stan poprzedni
let lastState = flow.get(stateKey) || "OFF";

// Histereza
const hysteresis = 0.5;

// Aktualny stan
let headState;

// Logika histerezy
if (lastState === "OFF" && vt2 < vt1 - hysteresis) {
    headState = "ON";
}
else if (lastState === "ON" && vt2 > vt1 + hysteresis) {
    headState = "OFF";
}
else {
    headState = lastState;
}

// Zapisujemy nowy stan
flow.set(stateKey, headState);

// Zwracamy to co chcesz ustawić
msg.payload = {
    occupied_heating_setpoint: vt1,
    valve_state: headState  // dodałem dla wygody testów
};

return msg;

Wyjście na Głowice i tak jak poprzedni nie spamuje node red jeżeli stan się nie zmienia nie wysyła nic (testuje)

// Pobranie temperatur
const vt1 = parseFloat(flow.get('ZadanaSypialnia')) || 22; // temperatura zadana
const vt2 = parseFloat(msg.payload);                      // temperatura aktualna

// Walidacja danych wejściowych
if (isNaN(vt2)) {
    node.warn("Brak poprawnej temperatury aktualnej (Sypialnia)");
    return null;
}

// Unikalne klucze pamięci
const stateKey = 'lastState_sypialnia';
const payloadKey = 'lastPayload_sypialnia';

// Odczyt poprzednich wartości
let lastState = flow.get(stateKey) || "OFF";
let lastPayload = flow.get(payloadKey) || {};

// Parametry sterowania
const hysteresis = 0.5;
let newState;

// Logika przełączania
if (lastState === "OFF" && vt2 < vt1 - hysteresis) {
    newState = "ON";
}
else if (lastState === "ON" && vt2 > vt1 + hysteresis) {
    newState = "OFF";
}
else {
    newState = lastState;
}

// Zapamiętanie nowego stanu zaworu
flow.set(stateKey, newState);

// Payload do wysyłki
let newPayload = {
    occupied_heating_setpoint: vt1,
    valve_state: newState
};

// Porównanie z poprzednim
let isSame =
    newPayload.occupied_heating_setpoint === lastPayload.occupied_heating_setpoint &&
    newPayload.valve_state === lastPayload.valve_state;

// Jeśli bez zmian → brak wysyłki
if (isSame) {
    return null;
}

// Zapis nowego payloadu
flow.set(payloadKey, newPayload);

msg.payload = newPayload;
return msg;


Bo to moje lokalne warunki. Mieszkam w bloku w z wielkiej płyt. Po drugie znam fizykę własnego mieszkania właśnie dzięki HA stąd takie a nie inne parametry.

.

Dwa kaloryfery - zegar z prawej strony to właśnie Bether Termostat który nimi steruje a pod spodem średnia temperatura z 3 czujników umieszczonych nisko.

u mnie też tak to działa grzej albo nie jak jest temperatura zadana kaloryfery są zakręcone, jeżeli nie to się odkręcają, w blokach płaci się za ciepły kaloryfer (ci co mają podzielniki ciepła) więc oszczędność wynika z tego że kaloryfery są zimne kiedy nie potrzeba wiem co pisze ostatni zwrot za grzanie 1800 zł

Wrzuć ostatnią wersję całego procesu to w weekend może poprawię. Jeszcze raz zapytam czy głowica ma boost? To znacznie upraszcza zadanie, wtedy część zadania robi głowica bepośrednio i autonomicznie. Nawet gdy coś padnie.
To AI, ktore pisze ten proces zbytnio to komplikuje. Normalny programista nie umieszcza komentarzy w kodzie🤣

Udało się zmodyfikować to chyba działa tak jak powinno, ale nadal w fazie testu
flows salon.json (15,3 KB)

A co z tym boostem, jaka to głowica?
Działa?..I tak to zrobię po swojemu

Aqara Radiator Thermostat E1 Termostat Głowica termostatyczna Zigbee 3.0 SRTS-A01 nie ma boost-a chyba

setup, climate (occupied_heating_setpoint, local_temperature, system_mode, preset), sensor, external_temperature_input, calibrated, calibrate, child_lock, window_detection, window_open, valve_detection, valve_alarm, away_preset_temperature, voltage, battery, power_outage_count, device_temperature, schedule, schedule_settings

Nie ma … choć AI sugeruje naciśnięcie 3x szybko przycisku mode i po osiągnieciu temperatury zadanej głowica automatycznie wróci do stanu normalnego

Zrobić pomocnik przycisku, który wywoła automatyzację… która przez mqtt wyśle setpoint… albo wywoła usługę setcośtam.
Piszę z fona więc rozpisywać się nie mogę.

ogarnąłem dlatego usunąłem wcześniejszy wpis :slight_smile: ale dziękuje

dodałem bufor między czujnikiem a termostatem
Temp.------------------------Podaje
21.2 stopni ----------------21 stopni
21.5 stopni ----------------21,5 stopni
21,8 stopni ----------------22 stopni
22.2 stopni ----------------22 stopni

let temp = parseFloat(msg.payload);
let fraction = temp - Math.floor(temp);

// --- Filtrowanie wg zasad ---
let filtered;
if (fraction < 0.25) {
    filtered = Math.floor(temp);
} else if (fraction > 0.75) {
    filtered = Math.ceil(temp);
} else {
    filtered = temp; // pozostawiamy tak jak jest
}

// --- Sprawdzanie, czy wartość się zmieniła ---
let lastValue = flow.get("lastTemp") || null;
if (lastValue === filtered) {
    // Wartość się nie zmieniła, nic nie wysyłamy
    return null;
}

// Zapis nowej wartości do kontekstu
flow.set("lastTemp", filtered);

// Wysyłamy tylko jeśli wartość się zmieniła
msg.payload = filtered;
return msg;

Wrzuciłem Twój JSON do GPT.
Masz jego opis:
Twoje flow działa tylko wtedy, gdy czujnik temperatury działa idealnie.
Jeśli czujnik się zawiesi, straci zasięg, padnie bateria lub Zigbee zgubi pakiet — Twój system NIE MA ŻADNEGO zabezpieczenia i:

  • albo grzeje klimatyzatorem cały czas (bo ostatni odczyt był niski),
  • albo nie grzeje wcale (bo ostatni odczyt był wysoki),
  • albo nie reaguje, bo wartość się nie zmieniła,
  • albo po restarcie flow context znika i logika zaczyna od złych danych.

Sterowanie ogrzewaniem MUSI mieć watchdog — warunek ‘brak odczytu X minut → wyłącz / ECO’.

Czyli to co Ci pisałem wcześniej i to bez GPT że nie możesz automatyzacji opierać wyłącznie na czujniku bateryjnym szt.1

Remedium => Nowa karta w NR :
flows (6).json (5,3 KB)

  1. W mqtt-local** – ustawić swój broker (albo podpiąć do istniejącego).
  2. W Z2M availability – SNZB-02D:
    • zmienić topic, jeśli ma inne friendly_name.
    • Upewnić się, że w Z2M ma availability: true.
  3. W nodzie Klimatyzacja Salon → OFF…:
    • podmienić climate.salon_klima na swoją encję klimy.
  4. Jak chcesz inną temperaturę ECO → w funkcji zmienić:
    const ecoTemp = 20;

Co to robi ?
To jest prosty watchdog: jak czujnik Zigbee padnie i przez 10 minut jest offline, to Node-RED sam wyłącza klimatyzację i zrzuca głowice na ECO. Dzięki temu awaria czujnika nie zrobi Ci sauny ani lodówki.