Średnia temp ciągle wynik NaN

Kombinuję już dłuższą chwilę z wyliczeniem średniej z dwóch czujników temp i jak bym tego nie zapisał w funkcji to zawsze wynik NaN. Co może być ? Oba czujniki to termometry , ta sama klasa urządzeń , więc powinna wystarczyć prosta matematyka . Próbowałem zapisać wszystko w jednym poleceniu

let wynik= (flow.get('a') + flow.get('b')) /2;

nie działa , zmieniłęm tak jak w załączonym przepływie , też lipa
flows sred.json (3,3 KB)
Ciągle to co na foto
1
Pomoże ktoś ?

Obie zmienne a i b istnieją po starcie?
Zanacz Output on Connect powinno wystarczyć, jeśli nie to jawnie konwertuj temp. do typu float

    let wynik= ( parseFloat(flow.get('a') )+ parseFloat(flow.get('b') )) /2;
1 polubienie

Output on Connect nie pomogło , parseFloat zrobiło robotę , Wirtualny Browar dla Ciebie :beer:
Gdyby ktoś miał podobny problem , to node function tak wyglada

Lepiej gdybyś zrozumiał dlaczego nie działało i się zastanowił gdy popełnisz go drugi raz :slight_smile:
Postaraj się to zrozumieć.
W językach programowania jest coś takiego jak typy danych

W rozpatrywanym przypadku otrzymujesz payload z temperaurą jako string - czyli ciąg znaków określających liczbę. Następnie, którą zapisujesz do zmiennej a i b.
… dla wyrażenia:
(flow.get(‘a’) + flow.get(‘b’)) /2;
ze względu na nawias pierwsze wykona się:
(flow.get(‘a’) + flow.get(‘b’)); ===> (a + b)
… przypadki gdy operujemy na stringach:

20 + 10 = 2010 ===> /2 = 1005
20.1 + 10 = 20.110 /2 = 10.055
10 + 20.1 = 1020.1 /2 = 510.05
10.1 + 20.1 = 10.120.1 /2 =NaN - ciąg 10.120.1 nie przedstawia liczby, którą da się /2
itp…
Jak sam widzisz otrzymujesz bzdurne wyniki lub wcale. Niby działa, więc błąd trudny do wykrycia :wink:
Jeśli nie wymusisz typu program, program próbuje użyć domyślnej konwersji wynikające z kontekstu.
W większości przypadków robi to trafnie. To jest powszechny błąd popełniany przez początkujących niezależnie w jakim języku programujesz.
Są kompilatory które nie dopuszczają deklaracji zmiennych “beztypowych” i wymagają świadomej konwersji. Tutaj jest to parseFloat()… tyle byłoby na temat programy.

Drugi aspekt to pewność działania w warunkach “brzegowy”. Niestety proces oparty jest o założenie, że wszystko działa i działa poprawnie.
W zupełnym oderwaniu od obiektu, który sterujesz - proces wyłoży się gdy:

  • do czasu gdy oba czujniki nie zgłoszą swoich temperatur proces nie będzie działał - nie istnieją jeszcze zmienne a i b;
  • gdy jeden z czujników przestanie działać to obliczenia będą błędne, a tym samym sterowanie.
    Po restarcie przestanie działać w ogóle, a sterowany obiekt nigdy nie przejdzie do stanu bezpiecznego. Hipotetycznie nie wyłączy się bojler :wink:
    W zależności od wagi procesu więcej czasu napisanie procedur “bezpieczeństwa” niż samego algorytmu działania.

Takie tam rozważania ogólne, wiec nie pisz że “… matka siedzi z tyłu…”

1 polubienie

Tak czy siak Browar się należy a Matka zawsze siedzi z przodu , teraz do brzegu , proszę w takim razie o wskazanie różnicy w tym co zrobiłem a tym co poniżej

return {
   on = { timer = { 'every 2 minutes' }
       }, 
    logging =   
    {
        level = domoticz.LOG_ERROR, 
        marker = 'średnia temp pokojowa',
    },    

   execute = function(dz, item)
       
       local Temp1 = dz.devices('Salon Temp/Wilg').temperature
       local Temp2 = dz.devices('Temp Biuro').temperature
       local decimals = 1
       local Tempavg = dz.utils.round((Temp1 + Temp2 ) / 2 , decimals)
       dz.devices('Temp Termostat').updateTemperature(Tempavg)
       dz.log('Średnia wyliczona temperatura: ' .. Tempavg, dz.LOG_INFO) 
   end
}

I pomijam tu uruchamianie skryptu od timera , bo w tym przykładowym przepływie go nie ma co nie znaczy, że tak zostanie.
Mam na mysli samą matematykę , w skrypcie dzvents , również pierwsze co się wykona to suma dwóch wartości , dla jasności powiem , że robiłem próby gdzie w nodach change zmieniałem string na number , ale to nic nie wnosiło . Mniejsza o to , ciekawy jestem wyjaśnienia różnicy bo w dzVents gdy zostawię tylko a+b i a = 22 natomiast b = 21 to dostanę sumę 43, a nie zmieniony string typu 2221.

PS.
W NR wskazuję wyraźnie o jakie wartości mi chodzi , wybierajac wskazania samej temperatury a nie np tamp + wilgotność , w dzVents muszę to wyraźnie zdekalarować bo w domoticz nie mam dwóch oddzielnych “czujników” tylko zespolony , zrozumiałbym że wyjdą bzdury gdy podstawię dwa różne typy np temp i odległość , ale wtedy powinienem dostać błąd , albo obie wartości konwertować do samych liczb. Dobra nie będę się rozwodził , chcę tylko poznać różnicę , jeśli mogę .
Dla spójności poniżej lokalne zmienne tak samo nazwane

       local a = dz.devices('Salon Temp/Wilg').temperature
       local b = dz.devices('Temp Biuro').temperature
       local decimals = 1
       local Tempavg = dz.utils.round((a + b ) / 2 , decimals)
       dz.devices('Temp Termostat').updateTemperature(Tempavg)
       dz.log('Średnia wyliczona temperatura: ' .. Tempavg, dz.LOG_INFO) 
   end
}

Matematycznie to jest to samo. Nie da się jednak wprost porównać dwóch systemów walutowych :slight_smile: . dzVentz to python a NR to Node.js.
Musiałbym się przenieś do pytona i ustalić zasady rzutowania typów.
Odpowiem więc pytaniem: jakiego typy dane zwraca funkcja ?

dz.devices('Salon Temp/Wilg').temperature

w pythonie wyrażenie (a+b) dla zmiennych string też zwróci “ab”, więc twórca dzVenz pewnie zadbał aby było właściwie.

Tak samo jest w dzVents , jeśli typ danych jest taki sam to operacje matematyczne wykonują się na surowych liczbach , jesli mamy czujnik np utworzony przez użytkownika , który zwraca string to robimy to wskazując wyraźnie że chcemy liczbę z tego wyciągnąć

local licznik=tonumber(dz.devices('coś tam ').state)

Stąd moja błędna interpretacja tego co się dzieje w NR .
Może jeszcze te względy bezpieczeństwa , w LUA bo to jest własnie Dzvents , jak któryś czujnik przestanie wysyłać swoje dane to skrypt przestanie się wykonywać i będzie sypał błędami , skoro przestanie się wykonywać , to mogę w prosty sposób ( sprawdzajac last-update ) tego “nowego” czujnika nazwijmy Średnia temp , wskazać czujnik rezerwowy. Co w przypadku Node.js ? Jak to się zachowa ?

…a widzisz :stuck_out_tongue:

… będzie pracował na ostatnim zapamiętanym stanie.

Prosta metoda sprawdzania czy dane są aktualne to po ich skonsumowaniu ustawić je na wartość niemożliwą np -280 C . Następnie sprawdzać czy wartość jest różna niż -280 w dowolnych wariantach.

Właśnie nie bardzo widzę , przecież w nodach events: state oba czujniki mają ten sam typ danych ( “temperatura”) , na dodatek w nodach change ustawiałem payload jako number , bezskutecznie.
Widzę , że przestawienie się , a najpierw zrozumienie procesów , to nie będzie takie cyk-pyk , To widzę na bank

Ok jak wartość nie jest różna niż -280 to co mogę ? Nie chodzi mi o to żeby zatrzymać proces. Muszę pewnie w node function ustawić dodatkowe wyjscie którym aktywuję np czujnik rezewa , Tak ?

…? zrzut od Ciebie
1
2

po prostu pamiętają o tym ustal sobie własny “styl”.

To już sam musisz określić: czy to jest krytyczne? Czy można pracować na podstawie tylko jednego?
Czy wymagane są dwa?
Tu nie ma recepty. Weź jeszcze pod uwagę, że czujniki nie meldują jednocześnie i nawet gdy temperatura się nie zmienia nie meldują wcale - a jest OK.
To były tylko takie rozważania ogólne, możesz równie dobrze taki fakt ignorować.

Dobra , to co wstawiłeś z mojego przepływu to efekt końcowy , nie uwzględnia wcześniejszych kombinacji , które robiłem , ale nie w tym rzecz . Powiedzmy że mój flow jest taki jak ten z którego czerpałeś te informacje , przerabiam go na taki ( sorki za fotkę ) ale chcę pokazać że wartość zmiennej się ustawiła na bzdurę


Czy możesz mi pomóc i napisać przykład funkcji , która będzie miałą dodatkowy out ? Tak żebym mógł ten proces przekierować na wypadek awarii ?

…zrobie po swojemu cały proces … please wait

@isom1266 …nie wiem co tam mieszałeś, ale działa na różne sposoby ( z zachowaniem zasad).
W tym przypadku proces lepiej napędzać okresowo injectem. Inne nieprzewidziane jeszcze przypadki mogą wystąpić, pokazałem tylko przykładowe (nie wiem np. “unavalible”?).
Załączam testowy przykład do zabawy.
flows (41).json (3,5 KB)

A da radę w tym jednym nodzie function utkać jeszcze obliczanie delty ? czy tez trzeba użyć dodatkowego i wtedy ew. coś w tym stylu ?

msg.payload = Number((flow.get('zas') - flow.get('pow')).toFixed(2))
msg.topic = "Delta";
return msg;

Jako dodatkowo obliczany parametr?
To ew. coś w tym stylu

msg.delta = Number((flow.get('zas') - flow.get('pow')).toFixed(2))

aby nie zmieniać payload, w którym jest średnia.

@RobinI30 Dzięki za przykład , podoba mi się wyeliminownie nodów change , pytasz co mieszałem ? Przyznam , że się zamotałęm i nie tu gdzie trzeba ustawiałem number zamiast string , zamiast tak jak Ty pokazałeś w state type , to jak to zmieniałem w if state .
Kolejna lekcja zaliczona . Teraz zapytam bo nie mogę jakoś zasymulować aktywacji out 4 w nodzie funkcji , kiedy tam się pojawi jakiś timestamp ? Rozumiem , że dwa wyjscia ze stanem samych czujników mogę sobie zmodyfikować do takiej postaci

let vt1 = flow.get('t1');
let vt2 = flow.get('t2');

if ((vt1 != -280) && (vt2 != -280)){
    let wynik = (vt1 + vt2) / 2;
    msg.payload = wynik.toFixed(1);
    return [msg,null, null, null];
}

if ((vt1 = -280)) {
    msg.payload = vt1;
    return [null, msg, null, null];
}

if ((vt2 = -280)) {
    msg.payload = vt2;
    return [null, null, msg, null];
}
return [null, null, null, msg];

I dodając na tych wyjściach kolejny node funkcji wygenerować powiadomienia na tel o niedziałajacym czyjniku . Czy jednak jakiś inny cel w tym miałeś ?
Pierwszy out nie budzi wątpliwości i tylko dodałem sobie ustawienie wyniku z jednym znakiem po przecinku , bo ta średnia wychodziła jak tasiemiec.
A tak przy okaji to Twoja pomoc więcej mi daje niż kilka godzin studiowania internetu. Dziękuje

… bo d…y dałem :wink:

if ((vt1 = -280))  powinno być if ((vt1 != -280))
if ((vt2 = -280))  powinno być if ((vt2 != -280))

To jest drugi najczęściej popełniany błąd i trudny do wykrycia - w warunkach if zawsze dwa znaki.
= a == robi różnicę
4 wyjście będzie “aktywne” gdy żaden czujnik nie odpowie - nie spełniowy żaden z warunków