Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. jwerlsdf

    NEWS

    • Monatsrückblick – September 2025

    • Neues Video "KI im Smart Home" - ioBroker plus n8n

    • Neues Video über Aliase, virtuelle Geräte und Kategorien

    J
    • Profile
    • Following 0
    • Followers 0
    • Topics 33
    • Posts 309
    • Best 5
    • Groups 2

    jwerlsdf

    @jwerlsdf

    Starter

    5
    Reputation
    83
    Profile views
    309
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    jwerlsdf Follow
    Pro Starter

    Best posts made by jwerlsdf

    • RE: SDM120 SDM72 SDM630 Modbus RS485 Stromzähler (W)LAN ioBroker

      @klassisch
      Also ich schäme mich ja fast, das zu schreiben, aber ich habe den Fehler gefunden. Ich habe bei der Verkabelung nicht richtig hingeschaut und habe eines der Kabel an die Erde geklemmt und nicht an B.
      Daher vielen Dank fur die Hilfe!!! Es geht nun alles.

      Jetzt habe ich noch eine kleine Frage. Wenn ich noch einen weiteren sdm630 verbaue kann ich vom anderen 630 in die Anschlüsse a und b gehen, sodass ich eine reihenschaltung einstelle und dann nur im sdm auf 002 die id stelle und im adapter ebenfalls auf 2 gehe?

      posted in Praktische Anwendungen (Showcase)
      J
      jwerlsdf
    • RE: [Vorlage] Android Wecker iobroker blockly

      @MisterBlinki
      versuch das mal. Beim export ist wohl ein bisschen zuviel reingekommen:
      Rollo Wecker.txt

      @smile
      Bei fehlen die Wecker-Objekte... Hast du noch weitere Einstellungen drinnen?!
      Wenn ich pushover nicht habe, kann ich dann auch den Versand per telegram zulassen?

      posted in Blockly
      J
      jwerlsdf
    • RE: zum aktuellen Datum Tage addieren

      @maik-0
      geht leider immer noch nicht. Das Datum bleibt auf dem heutigen Stand. Wie gesagt. Mit dem Zahlencode kann ich einen Tag addieren zum aktuellen Datum und es funktioniert. Es geht aber nur nicht mit mehreren Additionen/ Tagen.

      edit:
      Es lag tatsächlich an den "Nullen". Es waren zwei zu wenig. So wäre es richtig:

      86400000
      172800000
      259200000
      345600000
      432000000
      518400000
      604800000
      ...

      posted in Blockly
      J
      jwerlsdf
    • RE: Hilfe bei request -> http Umstellung Sonos Sprachausgabe

      @xbit
      Die sonos App auf die Version 80.x. Ging auch ein Firmware Update der sonos Boxen einher. So ganz genau kann ich es aber nicht mehr sagen. Aber mit dieser neuen Version gingen bei mir alle Probleme los.

      posted in Blockly
      J
      jwerlsdf
    • RE: exec befehl mit root Berechtigung (SONOSAPI)

      Hi,
      Ich hatte ein ähnliches Problem. Bei einem Neustart sollte ein Befehl an raspberry gesendet werden. Das PW sollte dabei mitgegeben werden. Mit blockly habe ich es nicht hinbekommen, mit Java gings.
      Das Skript macht folgendes. Es überprüft den Datenpunkt mpd info connect auf false. Ist dieser auf false, wird sich auf dem raspberry mit pw eingeloggt jnd der sudo Befehl abgewendet.

      Vielleicht hilft dir das Skript weiter. Habe dir noch einige Anmerkungen reingeschri3ben

      const { Client } = require('ssh2'); // Importiere die ssh2 Bibliothek
      
      // Konfiguration für den Raspberry Pi MPD (IP, Benutzername und Passwort)
      const raspberryMPDConfig = {
        host: '192.168.XXX.XX', // IP-Adresse von Raspberry Pi MPD
        port: 22,
        username: 'pi', // Benutzername auf Raspberry Pi MPD
        password: 'XXX' // Passwort für den Benutzer
      };
      
      let sshErrorLogged = false; // Flag, um Fehler nur einmal zu protokollieren
      
      // Funktion, die den Befehl an Raspberry Pi MPD sendet
      function sendCommandToRaspberryMPD() {
        const conn = new Client();
      
        // Verbindung zu Raspberry Pi MPD herstellen
        conn.on('ready', () => {
          // Den Befehl "sudo service mpd start" ausführen
          conn.exec('sudo service mpd start', (err, stream) => {
            if (err) {
              if (!sshErrorLogged) {
                console.error('Fehler beim Ausführen des Befehls:', err); // Fehler nur einmal loggen
                sshErrorLogged = true; // Fehler flag setzen
              }
              conn.end();
              return;
            }
      
            stream.on('data', () => {
              // Keine Ausgabe mehr aufzeichnen
            });
      
            stream.on('close', () => {
              conn.end(); // Verbindung schließen
            });
          });
        }).on('error', () => {
          if (!sshErrorLogged) {
            console.error('Fehler bei der SSH-Verbindung.'); // Fehler nur einmal loggen
            sshErrorLogged = true; // Fehler flag setzen
          }
        }).connect(raspberryMPDConfig);
      }
      
      // Event-Listener für den Datenpunkt mpd.0.info.connection
      on({ id: 'mpd.0.info.connection', val: false }, async (obj) => {
        let value = obj.state.val;  // Der aktuelle Wert des Datenpunkts
        let oldValue = obj.oldState.val;  // Der vorherige Wert des Datenpunkts
      
        if (value === false) {
          sendCommandToRaspberryMPD();
        } else {
          sshErrorLogged = false; // Fehlerflag zurücksetzen, wenn der Wert nicht mehr false ist
        }
      });
      
      posted in Blockly
      J
      jwerlsdf

    Latest posts made by jwerlsdf

    • RE: Homematic IP Wand und Heizkörperthermostate

      @paul53 said in Homematic IP Wand und Heizkörperthermostate:

      Die Reaktion auf den Fensterkontakt kann man vereinfachen (nur ein Trigger!):

      Stimmt. Habe ich entsprechend geändert.

      "Ist die Gruppe nicht ein virtuelles Device unter einer eigenen HM-RPC-Instanz?"
      Habe ich leider nicht gefunden. Aber passt schon. So funktioniert es nun wenigstens.

      posted in Blockly
      J
      jwerlsdf
    • RE: Homematic IP Wand und Heizkörperthermostate

      @paul53
      Ich probiere auch mal deine Variante aus. Ist "Sollwert" der Datenpunkt "hm-rpc.XXX.SET_POINT_TEMPERATURE"?

      Hat sich erledigt. Vielen Dank Paul! Habe noch dein Skript angepasst, sodass beim WT2, wenn Fenster offen, die 12 Grad und Fenster Auf Symbol angezeigt wird und wenn das Fenster zu ist, der SOll-Wert von der Gruppe genommen wird, ohne das eine Schleife passiert.

      Hier das Skript.

      <xml xmlns="https://developers.google.com/blockly/xml">
       <variables>
         <variable type="timeout" id="timeout">timeout</variable>
       </variables>
       <block type="comment" id="{Y]#=u$1OQZm-ay49]cq" x="-712" y="-387">
         <field name="COMMENT">Gruppe (Terrasse)</field>
         <next>
           <block type="on" id="pT757H3*3srntxuFOR#;">
             <field name="OID">hm-rpc.1.001CDD89B76720.1.SET_POINT_TEMPERATURE</field>
             <field name="CONDITION">ne</field>
             <field name="ACK_CONDITION"></field>
             <statement name="STATEMENT">
               <block type="controls_if" id="l45luZ?V}LQmwdr?1D}4">
                 <value name="IF0">
                   <block type="logic_compare" id="s61Zr|3x-%uV{}i.Pf-Q">
                     <field name="OP">NEQ</field>
                     <value name="A">
                       <block type="on_source" id="z+t9x/,qe+BZ!J8!kKnt">
                         <field name="ATTR">state.c</field>
                       </block>
                     </value>
                     <value name="B">
                       <block type="global_var" id="%n~bb})e4*EQtG_d~9B#">
                         <field name="VAR">scriptName</field>
                       </block>
                     </value>
                   </block>
                 </value>
                 <statement name="DO0">
                   <block type="comment" id="G=yl+ANln9:e/4a2^d/E">
                     <field name="COMMENT">WT2</field>
                     <next>
                       <block type="control" id="TZH@F3tJ5HOIq?h5unYQ">
                         <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
                         <field name="OID">hm-rpc.1.001CDD89B76724.1.SET_POINT_TEMPERATURE</field>
                         <field name="WITH_DELAY">FALSE</field>
                         <value name="VALUE">
                           <block type="on_source" id=":v_SIj~}U3301{tWSU}:">
                             <field name="ATTR">state.val</field>
                           </block>
                         </value>
                       </block>
                     </next>
                   </block>
                 </statement>
               </block>
             </statement>
             <next>
               <block type="comment" id="a9HXs6g6*}6tjCsIg[6_">
                 <field name="COMMENT">WT2 (Eingang)</field>
                 <next>
                   <block type="on" id="wO?$=+.c5c[SX9Hid3ZW">
                     <field name="OID">hm-rpc.1.001CDD89B76724.1.SET_POINT_TEMPERATURE</field>
                     <field name="CONDITION">ne</field>
                     <field name="ACK_CONDITION"></field>
                     <statement name="STATEMENT">
                       <block type="controls_if" id="cPS(.,FSSO8gV[wif)SE">
                         <value name="IF0">
                           <block type="logic_multi_and" id="$VLZun|6I$hDr2,Q*`oC">
                             <mutation xmlns="http://www.w3.org/1999/xhtml" items="2"></mutation>
                             <value name="AND0">
                               <block type="logic_compare" id="/*S+cbX}G]T[qCob=V_Z">
                                 <field name="OP">NEQ</field>
                                 <value name="A">
                                   <block type="on_source" id=":47h_L5M/2zz~KXB(UcW">
                                     <field name="ATTR">state.c</field>
                                   </block>
                                 </value>
                                 <value name="B">
                                   <block type="global_var" id="c-|mC)qb)1#dx[z97yrt">
                                     <field name="VAR">scriptName</field>
                                   </block>
                                 </value>
                               </block>
                             </value>
                             <value name="AND1">
                               <block type="logic_compare" id="rBE?}M`jfY/0y@oXmNJi">
                                 <field name="OP">EQ</field>
                                 <value name="A">
                                   <block type="get_value" id="[5]%)7@^7_d*n?ihQiU%">
                                     <field name="ATTR">val</field>
                                     <field name="OID">hm-rpc.1.00109F29B2DA40.1.STATE</field>
                                   </block>
                                 </value>
                                 <value name="B">
                                   <block type="math_number" id="wk2?0_%9AJ`NbSiCnN.6">
                                     <field name="NUM">0</field>
                                   </block>
                                 </value>
                               </block>
                             </value>
                           </block>
                         </value>
                         <statement name="DO0">
                           <block type="comment" id="NA%$CR?mka9`lHpk3ke{">
                             <field name="COMMENT">Gruppe</field>
                             <next>
                               <block type="control" id="B4%#e4rz{mF%w)=Ooq@O">
                                 <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
                                 <field name="OID">hm-rpc.1.001CDD89B76720.1.SET_POINT_TEMPERATURE</field>
                                 <field name="WITH_DELAY">FALSE</field>
                                 <value name="VALUE">
                                   <block type="on_source" id="*l}`+Wbi5#8Y.CG3)dsz">
                                     <field name="ATTR">state.val</field>
                                   </block>
                                 </value>
                                 <next>
                                   <block type="control" id="gzP#;{cO%TE2a(w;#:Yl">
                                     <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
                                     <field name="OID">hm-rpc.1.002A9F29AE0076.1.SET_POINT_TEMPERATURE</field>
                                     <field name="WITH_DELAY">FALSE</field>
                                     <value name="VALUE">
                                       <block type="on_source" id="W807ER2:9`]h-:^te,C5">
                                         <field name="ATTR">state.val</field>
                                       </block>
                                     </value>
                                     <next>
                                       <block type="control" id="TH*M%dJAR!e8lg#^vV]%">
                                         <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
                                         <field name="OID">hm-rpc.1.002A9F29AE007E.1.SET_POINT_TEMPERATURE</field>
                                         <field name="WITH_DELAY">FALSE</field>
                                         <value name="VALUE">
                                           <block type="on_source" id="/6J?g/gf/J03[k,GJTHD">
                                             <field name="ATTR">state.val</field>
                                           </block>
                                         </value>
                                       </block>
                                     </next>
                                   </block>
                                 </next>
                               </block>
                             </next>
                           </block>
                         </statement>
                       </block>
                     </statement>
                     <next>
                       <block type="on" id="IRA(~4ty|7Mi[bo%ADB*">
                         <field name="OID">hm-rpc.1.00109F29B2DA40.1.STATE</field>
                         <field name="CONDITION">ne</field>
                         <field name="ACK_CONDITION"></field>
                         <statement name="STATEMENT">
                           <block type="controls_if" id="-CDUSoG=eSok?ew6a|7$">
                             <mutation elseif="1"></mutation>
                             <value name="IF0">
                               <block type="logic_compare" id="~%Uryn_d%Vg5xf|nNiAr">
                                 <field name="OP">EQ</field>
                                 <value name="A">
                                   <block type="get_value" id="(bq/Zx#~}i5z]SF#_q+1">
                                     <field name="ATTR">val</field>
                                     <field name="OID">hm-rpc.1.00109F29B2DA40.1.STATE</field>
                                   </block>
                                 </value>
                                 <value name="B">
                                   <block type="math_number" id="P(/sOpOc]^5,1hL5N]HK">
                                     <field name="NUM">1</field>
                                   </block>
                                 </value>
                               </block>
                             </value>
                             <statement name="DO0">
                               <block type="comment" id="Gc%nO;%^0.t-7DmJzo#a">
                                 <field name="COMMENT">WT2</field>
                                 <next>
                                   <block type="control" id="4T0~IV5n30U[[-l]7m6_">
                                     <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
                                     <field name="OID">hm-rpc.1.001CDD89B76724.1.SET_POINT_TEMPERATURE</field>
                                     <field name="WITH_DELAY">FALSE</field>
                                     <value name="VALUE">
                                       <block type="math_number" id="i_GLDxR[.0xI]yYEz2ox">
                                         <field name="NUM">12</field>
                                       </block>
                                     </value>
                                     <next>
                                       <block type="control" id="cY%oiFRJaFQkz^9?|d2d">
                                         <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
                                         <field name="OID">hm-rpc.1.001CDD89B76724.1.WINDOW_STATE</field>
                                         <field name="WITH_DELAY">FALSE</field>
                                         <value name="VALUE">
                                           <block type="math_number" id="~tq`s)J(6e@--d+p}u^;">
                                             <field name="NUM">1</field>
                                           </block>
                                         </value>
                                       </block>
                                     </next>
                                   </block>
                                 </next>
                               </block>
                             </statement>
                             <value name="IF1">
                               <block type="logic_compare" id="Q7;K6ggUo-Rxpy%I5DW{">
                                 <field name="OP">EQ</field>
                                 <value name="A">
                                   <block type="get_value" id="PTYt;vydFkO8qKs[!8_#">
                                     <field name="ATTR">val</field>
                                     <field name="OID">hm-rpc.1.00109F29B2DA40.1.STATE</field>
                                   </block>
                                 </value>
                                 <value name="B">
                                   <block type="math_number" id="@iUwEkzhmne`v{awbrV{">
                                     <field name="NUM">0</field>
                                   </block>
                                 </value>
                               </block>
                             </value>
                             <statement name="DO1">
                               <block type="control" id="@%E~;21$:RGnxXmAuX0?">
                                 <mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
                                 <field name="OID">hm-rpc.1.001CDD89B76724.1.WINDOW_STATE</field>
                                 <field name="WITH_DELAY">FALSE</field>
                                 <value name="VALUE">
                                   <block type="math_number" id="se~_sx}@GZ|lin,RMVFk">
                                     <field name="NUM">0</field>
                                   </block>
                                 </value>
                               </block>
                             </statement>
                           </block>
                         </statement>
                       </block>
                     </next>
                   </block>
                 </next>
               </block>
             </next>
           </block>
         </next>
       </block>
       <block type="on_ext" id="tBRS+crN0bIA*b9?V;{," x="163" y="-262">
         <mutation xmlns="http://www.w3.org/1999/xhtml" items="1"></mutation>
         <field name="CONDITION">ne</field>
         <field name="ACK_CONDITION"></field>
         <value name="OID0">
           <shadow type="field_oid" id="6a:*dBd4Rn:lWwGQiJpP">
             <field name="oid">hm-rpc.1.00109F29B2DA40.1.STATE</field>
           </shadow>
         </value>
         <statement name="STATEMENT">
           <block type="controls_if" id="0P[vT/#03AT-eA9X2Lr^">
             <mutation elseif="1"></mutation>
             <value name="IF0">
               <block type="logic_negate" id="_nTB0N(;-ir0*n.5[jHl">
                 <value name="BOOL">
                   <block type="get_value" id="~t3^`/nsUyEy2Ok:hI%!">
                     <field name="ATTR">val</field>
                     <field name="OID">hm-rpc.1.00109F29B2DA40.1.STATE</field>
                   </block>
                 </value>
               </block>
             </value>
             <statement name="DO0">
               <block type="timeouts_cleartimeout" id="^]4b94]%+YeX_8*0:b1C">
                 <field name="NAME">timeout</field>
               </block>
             </statement>
             <value name="IF1">
               <block type="logic_negate" id="GKgV-_`H7ypD+5^WYVyp">
                 <value name="BOOL">
                   <block type="timeouts_gettimeout" id="I?3m1sX~Q1LB*PI{Nhe0">
                     <field name="NAME">timeout</field>
                   </block>
                 </value>
               </block>
             </value>
             <statement name="DO1">
               <block type="timeouts_settimeout" id="yMgaU*:?me{t3CVn|4$5">
                 <field name="NAME">timeout</field>
                 <field name="DELAY">10</field>
                 <field name="UNIT">min</field>
                 <statement name="STATEMENT">
                   <block type="telegram" id="]J:G_X3{e3Qmq6]Y6n],">
                     <field name="INSTANCE"></field>
                     <field name="LOG"></field>
                     <field name="SILENT">FALSE</field>
                     <field name="PARSEMODE">default</field>
                     <field name="ESCAPING">FALSE</field>
                     <field name="DISABLE_WEB_PAGE_PREVIEW">FALSE</field>
                     <value name="MESSAGE">
                       <shadow type="text" id="pfWG1cd=-*gqOPi6m2a,">
                         <field name="TEXT">Die Wohnzimmertür ist seit 10 Minuten offen.</field>
                       </shadow>
                     </value>
                   </block>
                 </statement>
               </block>
             </statement>
           </block>
         </statement>
       </block>
      </xml>
      

      Die Nachtabsenkung habe ich tatsächlich über die CCU gemacht. Urlaubmodus mache ich wie angezeigt. WIe gesagt, Danke Paul!

      posted in Blockly
      J
      jwerlsdf
    • RE: Homematic IP Wand und Heizkörperthermostate

      @paul53 said in Homematic IP Wand und Heizkörperthermostate:

      Wozu benötigt man dieses WT?

      Ganz einfach. Weil Frau das Thermostat vom Flur aus steuern möchte und nicht jedes Mal ans Ende des Raumes gehen möchte.

      Ich habe mich nun mit Hilfe von ChatGPT mal herangetastet und es funktioniert nun so wie ich es möchte. Hier die Beschreibung

      1. Wandthermostat 1 misst die Raumtemperatur.
      2. An den Wandthermostat 1 und 2 können die Soll-Werte manuell geschrieben werden. Wird an WTH1 der Soll-Wert gesetzt, wird dieser Wert ebenfalls bei WTH2 und bei allen Heizköperthermostaten gesetzt und umgedreht.
      3. Fensterkontaktschalter: Ist die Tür offen, wird 12 Grad bei allen Geräten eingestellt. Weiterhin wird der window.state auf open gesetzt. Der letztgeschriebene Soll-Wert wird zuvor im folgenden Datenpunkt geschrieben: "0_userdata.0.Raumtemperatur.LastTemp" (Bitte anlegen, wer das Skript benutzen möchte). Wenn nun die Tür wieder geschlossen wird, wird der Soll-Wert von LastTemp benutzt und bei allen Geräten geschrieben.
      4. Nachtabsenkung: Es können die Tage (Mo-So) mit den Uhrzeiten ausgewählt werden und die Temperatur eingestellt werden.
      5. Push-Nachricht per Telegram, wenn das Fenster länger als XX Minuten offen ist.

      To-Do:
      Ferienmodus mit dem Feiertage-Adapter verknüpfen.

      Hier nun das Skript. PS. Das Thema ist doch eher nun bei Java aufgehoben als hier bei Blockly.

      // === KONSTANTEN ===
      const THERMOSTAT_1 = 'hm-rpc.1.001CDD89B76720.1.SET_POINT_TEMPERATURE';
      const THERMOSTAT_2 = 'hm-rpc.1.001CDD89B76724.1.SET_POINT_TEMPERATURE';
      const HEIZKOERPER_1 = 'hm-rpc.1.002A9F29AE0076.1.SET_POINT_TEMPERATURE';
      const HEIZKOERPER_2 = 'hm-rpc.1.002A9F29AE007E.1.SET_POINT_TEMPERATURE';
      
      const FENSTERKONTAKTE = [
         'hm-rpc.1.00109F29B2DA40.1.STATE',
         // weitere Fensterkontakte hier eintragen
      ];
      
      const LAST_TEMP = '0_userdata.0.Raumtemperatur.LastTemp';
      const FENSTER_OFFEN_TEMP = 12;
      
      // === NACHTABSENKUNG ===
      const NACHTABSENKUNG = {
         Montag:    { aktiv: true, absenkZeit: '22:30', rueckZeit: '09:00' },
         Dienstag:  { aktiv: true, absenkZeit: '22:30', rueckZeit: '09:00' },
         Mittwoch:  { aktiv: true, absenkZeit: '22:30', rueckZeit: '09:00' },
         Donnerstag:{ aktiv: true, absenkZeit: '22:30', rueckZeit: '09:00' },
         Freitag:   { aktiv: true, absenkZeit: '23:30', rueckZeit: '09:00' },
         Samstag:   { aktiv: true, absenkZeit: '23:30', rueckZeit: '06:00' },
         Sonntag:   { aktiv: true, absenkZeit: '22:30', rueckZeit: '06:00' },
      };
      const NACHT_ABSENK_TEMP = 19;
      const NACHT_RUECK_TEMP = 21;
      
      // === FENSTER-ÜBERWACHUNG (Telegram Warnung bei langem Öffnen) ===
      const ENABLE_LONG_OPEN_WARNING = true;
      const LONG_OPEN_MINUTES = 10;
      const PUSH_MESSAGE_TARGET = 'telegram.0';
      const PUSH_RECIPIENTS = [];  // Empfänger: Leer = alle, sonst User IDs als Array: ['123456789', '987654321']
      
      // === LOGGING ===
      // Log-Level: 0 = keine Logs, 1 = nur Push, 2 = alle Infos
      const LOG_LEVEL = 0;
      function logInfo(msg, level = 2) {
         if (LOG_LEVEL >= level) console.log(`[Info] ${msg}`);
      }
      
      // === CACHE ===
      const cache = {};
      const CACHE_TIMEOUT = 3000;
      function setCached(id, value) {
         if (cache[id]?.timer) clearTimeout(cache[id].timer);
         cache[id] = {
             value,
             timer: setTimeout(() => delete cache[id], CACHE_TIMEOUT)
         };
      }
      function isCached(id, value) {
         return cache[id]?.value === value;
      }
      
      // === HELPER ===
      function writeIfChanged(id, value) {
         const current = getState(id)?.val;
         if (Number(current) !== Number(value)) {
             setState(id, value);
             setCached(id, value);
             logInfo(`[Write] ${id} gesetzt auf ${value} (alt: ${current})`);
         }
      }
      
      function getWindowStateId(tempId) {
         return tempId.replace('SET_POINT_TEMPERATURE', 'WINDOW_STATE');
      }
      
      function isWindowOpen() {
         for (const id of FENSTERKONTAKTE) {
             const val = getState(id)?.val;
             if (val === true || val === 1 || val === 'true') {
                 return true;
             }
         }
         return false;
      }
      
      // === SYNC WANDTHERMOSTATE UND HEIZKÖRPER ===
      function syncThermostats(source, target) {
         on({ id: source, change: "ne" }, (obj) => {
             const newValue = obj.state.val;
      
             if (isWindowOpen()) {
                 logInfo(`[Sync] Änderung ignoriert – Fenster offen: ${source} → ${newValue}°C`);
                 return;
             }
      
             if (isCached(source, newValue)) return;
      
             logInfo(`[Sync] Änderung erkannt bei ${source}: ${newValue}°C`);
      
             writeIfChanged(target, newValue);
             writeIfChanged(HEIZKOERPER_1, newValue);
             writeIfChanged(HEIZKOERPER_2, newValue);
      
             setState(LAST_TEMP, newValue);
         });
      }
      
      // === FENSTER-LOGIK ===
      let longOpenTimer = null;
      let longOpenNotified = false;
      
      function startLongOpenTimer() {
         if (!ENABLE_LONG_OPEN_WARNING || longOpenTimer) return;
         longOpenNotified = false;
         longOpenTimer = setTimeout(() => {
             if (isWindowOpen()) {
                 sendPush(`🚪 Das Fenster ist seit über ${LONG_OPEN_MINUTES} Minuten geöffnet!`);
                 longOpenNotified = true;
             }
         }, LONG_OPEN_MINUTES * 60 * 1000);
         logInfo(`[Fenster-Überwachung] Timer gestartet (${LONG_OPEN_MINUTES} Min.)`);
      }
      
      function stopLongOpenTimer() {
         if (longOpenTimer) {
             clearTimeout(longOpenTimer);
             longOpenTimer = null;
             logInfo(`[Fenster-Überwachung] Timer gestoppt.`);
         }
         longOpenNotified = false;
      }
      
      function sendPush(msg) {
         if (!PUSH_MESSAGE_TARGET) return;
         logInfo(`[Push] Sende Nachricht: ${msg}`, 1);
      
         if (Array.isArray(PUSH_RECIPIENTS) && PUSH_RECIPIENTS.length) {
             PUSH_RECIPIENTS.forEach(userId => {
                 sendTo(PUSH_MESSAGE_TARGET, "send", {
                     user: userId,
                     text: msg
                 });
             });
         } else {
             sendTo(PUSH_MESSAGE_TARGET, "send", {
                 text: msg
             });
         }
      }
      
      function handleWindowChange() {
         const open = isWindowOpen();
         logInfo(`[Fensterstatus] Fenster ist jetzt: ${open ? 'OFFEN' : 'GESCHLOSSEN'}`);
      
         if (open) {
             const currentTemp = getState(THERMOSTAT_1)?.val;
             if (typeof currentTemp === 'number') {
                 setState(LAST_TEMP, currentTemp);
                 logInfo(`[Fenster] Offen – Sollwert gespeichert: ${currentTemp}°C`);
             } else {
                 logInfo(`[Fenster] Offen – Keine gültige Temperatur zum Speichern gefunden: ${currentTemp}`);
             }
      
             [THERMOSTAT_1, THERMOSTAT_2, HEIZKOERPER_1, HEIZKOERPER_2].forEach(id => {
                 writeIfChanged(id, FENSTER_OFFEN_TEMP);
                 const windowStateId = getWindowStateId(id);
                 writeIfChanged(windowStateId, 1);
             });
      
             startLongOpenTimer();
         } else {
             let savedTemp = getState(LAST_TEMP)?.val;
             if (typeof savedTemp !== 'number') savedTemp = 21;
      
             logInfo(`[Fenster] Geschlossen – Wiederherstellung auf: ${savedTemp}°C`);
      
             [THERMOSTAT_1, THERMOSTAT_2, HEIZKOERPER_1, HEIZKOERPER_2].forEach(id => {
                 writeIfChanged(id, savedTemp);
                 const windowStateId = getWindowStateId(id);
                 writeIfChanged(windowStateId, 0);
             });
      
             stopLongOpenTimer();
         }
      }
      
      FENSTERKONTAKTE.forEach(id => {
         on({ id: id, change: "ne" }, (obj) => {
             logInfo(`[Event] Fensterkontakt ${id} geändert: ${obj.state.val}`);
             handleWindowChange();
         });
      });
      
      // === NACHTABSENKUNG ===
      function getWeekdayName(dayIndex) {
         return ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'][dayIndex];
      }
      
      function scheduleNightMode() {
         const now = new Date();
         const dayIndex = now.getDay();
         const dayName = getWeekdayName(dayIndex);
         const config = NACHTABSENKUNG[dayName];
      
         if (!config?.aktiv) {
             logInfo(`[Nachtabsenkung] Für ${dayName} deaktiviert.`);
             scheduleNextNightMode();
             return;
         }
      
         const [abHour, abMinute] = config.absenkZeit.split(':').map(Number);
         const [rueckHour, rueckMinute] = config.rueckZeit.split(':').map(Number);
      
         const absenkTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), abHour, abMinute);
         const rueckTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), rueckHour, rueckMinute);
      
         if (rueckTime <= absenkTime) rueckTime.setDate(rueckTime.getDate() + 1);
      
         const timeUntilDown = (absenkTime - now > 0) ? (absenkTime - now) : (absenkTime.getTime() + 24*60*60*1000 - now.getTime());
         const timeUntilUp = (rueckTime - now > 0) ? (rueckTime - now) : (rueckTime.getTime() + 24*60*60*1000 - now.getTime());
      
         setTimeout(() => {
             if (!isWindowOpen()) {
                 logInfo(`[Nachtabsenkung] Absenkung auf ${NACHT_ABSENK_TEMP}°C (${dayName})`);
                 [THERMOSTAT_1, THERMOSTAT_2, HEIZKOERPER_1, HEIZKOERPER_2].forEach(id => {
                     writeIfChanged(id, NACHT_ABSENK_TEMP);
                 });
             } else {
                 logInfo(`[Nachtabsenkung] Absenkung übersprungen wegen offenem Fenster (${dayName})`);
             }
             scheduleNextNightMode();
         }, timeUntilDown);
      
         setTimeout(() => {
             if (!isWindowOpen()) {
                 logInfo(`[Nachtabsenkung] Rückkehr auf ${NACHT_RUECK_TEMP}°C (${dayName})`);
                 [THERMOSTAT_1, THERMOSTAT_2, HEIZKOERPER_1, HEIZKOERPER_2].forEach(id => {
                     writeIfChanged(id, NACHT_RUECK_TEMP);
                 });
             } else {
                 logInfo(`[Nachtabsenkung] Rückkehr übersprungen wegen offenem Fenster (${dayName})`);
             }
             scheduleNextNightMode();
         }, timeUntilUp);
      
         logInfo(`[Nachtabsenkung] Zeitplan gesetzt für ${dayName}: Absenkzeit ${config.absenkZeit}, Rückkehrzeit ${config.rueckZeit}`);
      }
      
      function scheduleNextNightMode() {
         const now = new Date();
         now.setHours(0, 0, 0, 0);
         now.setDate(now.getDate() + 1);
         const nextDay = now.getDay();
         setTimeout(scheduleNightMode, 24*60*60*1000); // Jeden Tag neu planen
      }
      
      scheduleNightMode();
      
      // === SYNC THERMOSTATE ===
      syncThermostats(THERMOSTAT_1, THERMOSTAT_2);
      syncThermostats(THERMOSTAT_2, THERMOSTAT_1);
      
      // --- Skript Ende ---
      
      

      posted in Blockly
      J
      jwerlsdf
    • RE: Homematic IP Wand und Heizkörperthermostate

      @paul53
      Ein Wandthermostat ist beim Eingang in den Raum. Leider ist daneben der Kachelofen. Das zweite Thermostat ist gegenüberliegende vom Kamin am Ende des Raumes.
      Unabhängig vom Zustand des Kamin habe ich bis zu einem Grad Unterschied.
      Es ist keine Gruppensteuerung mit zwei Wandthermostate möglich über die CCU3.
      Ich werde mich morgen noch einmal dran setzt.
      Setpoint ist doch nur den Wert setzten, aber durch den Wert wird doch nicht automatisch das Ventil geöffnet. Ich muss doch mit einem datenpunkt sorgen, dass er das Ventil auffährt und wieder zu fährt, wenn gemessener Wert und Zielwert identisch ist?!

      posted in Blockly
      J
      jwerlsdf
    • RE: Homematic IP Wand und Heizkörperthermostate

      @tt-tom
      Über die CCU3 nicht über die App

      posted in Blockly
      J
      jwerlsdf
    • Homematic IP Wand und Heizkörperthermostate

      Hallo,
      ich habe folgender Aufbau:
      Zwei Wandthermostate,
      zwei Heizkörperthermostate und Fensterkontaktschalter.

      Wandthermostat 1 soll die Temperaturmessung übernehmen

      Über Wandthermostat 1 und 2 soll die manuelle Regelung vorgenommen werden. Dementsprechend muss, wenn ich WT1 manuell ändere in WT2 der Wert entsprechend angepasst werden und umgekehrt.

      Leider geht eine Direktverknüpfung mit diesem Szenario nicht mit homematic.
      Wie muss ich nun die Programmierung vornehmen? Steuere ich die Ventile maximal für einen vorgegeben Zeitpunkt mit auf? Welche Datenpunkte benötige ich? Würde mir bitte jemand auf die Sprünge helfen?

      posted in Blockly
      J
      jwerlsdf
    • RE: Test/Support für Adapter rssfeed und vis-2-widgets-rssfeed

      @oliverio
      DAnke, dachte, es geht auch hiermit.
      Jetzt habe ich es mit inventwo gelöst. Nur noch eine Frage dazu, dann höre ich hier auf: Im editor funktioniert der Lauftext, im Runtime leider nicht, bleibt also an der selben stelle stehen. Woran könnte es liegen?

      posted in Tester
      J
      jwerlsdf
    • RE: Test/Support für Adapter rssfeed und vis-2-widgets-rssfeed

      Hallo,
      ich habe VIS1. Wie kann ich denn einen festen Textbaustein im Lauffeld anzeigen lassen? Könnte mir bitte jemand auf die Sprünge helfen?

      posted in Tester
      J
      jwerlsdf
    • RE: exec befehl mit root Berechtigung (SONOSAPI)

      Hi,
      Ich hatte ein ähnliches Problem. Bei einem Neustart sollte ein Befehl an raspberry gesendet werden. Das PW sollte dabei mitgegeben werden. Mit blockly habe ich es nicht hinbekommen, mit Java gings.
      Das Skript macht folgendes. Es überprüft den Datenpunkt mpd info connect auf false. Ist dieser auf false, wird sich auf dem raspberry mit pw eingeloggt jnd der sudo Befehl abgewendet.

      Vielleicht hilft dir das Skript weiter. Habe dir noch einige Anmerkungen reingeschri3ben

      const { Client } = require('ssh2'); // Importiere die ssh2 Bibliothek
      
      // Konfiguration für den Raspberry Pi MPD (IP, Benutzername und Passwort)
      const raspberryMPDConfig = {
        host: '192.168.XXX.XX', // IP-Adresse von Raspberry Pi MPD
        port: 22,
        username: 'pi', // Benutzername auf Raspberry Pi MPD
        password: 'XXX' // Passwort für den Benutzer
      };
      
      let sshErrorLogged = false; // Flag, um Fehler nur einmal zu protokollieren
      
      // Funktion, die den Befehl an Raspberry Pi MPD sendet
      function sendCommandToRaspberryMPD() {
        const conn = new Client();
      
        // Verbindung zu Raspberry Pi MPD herstellen
        conn.on('ready', () => {
          // Den Befehl "sudo service mpd start" ausführen
          conn.exec('sudo service mpd start', (err, stream) => {
            if (err) {
              if (!sshErrorLogged) {
                console.error('Fehler beim Ausführen des Befehls:', err); // Fehler nur einmal loggen
                sshErrorLogged = true; // Fehler flag setzen
              }
              conn.end();
              return;
            }
      
            stream.on('data', () => {
              // Keine Ausgabe mehr aufzeichnen
            });
      
            stream.on('close', () => {
              conn.end(); // Verbindung schließen
            });
          });
        }).on('error', () => {
          if (!sshErrorLogged) {
            console.error('Fehler bei der SSH-Verbindung.'); // Fehler nur einmal loggen
            sshErrorLogged = true; // Fehler flag setzen
          }
        }).connect(raspberryMPDConfig);
      }
      
      // Event-Listener für den Datenpunkt mpd.0.info.connection
      on({ id: 'mpd.0.info.connection', val: false }, async (obj) => {
        let value = obj.state.val;  // Der aktuelle Wert des Datenpunkts
        let oldValue = obj.oldState.val;  // Der vorherige Wert des Datenpunkts
      
        if (value === false) {
          sendCommandToRaspberryMPD();
        } else {
          sshErrorLogged = false; // Fehlerflag zurücksetzen, wenn der Wert nicht mehr false ist
        }
      });
      
      posted in Blockly
      J
      jwerlsdf
    • RE: Real Weather (Bald)

      Hallo,
      es ist schon lange her, aber ich versuche es doch noch einmal hier. Ich hoffe, es kann mir jemand helfen:

      Ich habe den Code folgendermaßen geändert, da dieser Fehler produziert hat. Jetzt schaut der COde bei mir so aus, aber ich bekomme folgenden Fehler:

      ImageNumber ist undefined
      

      Hier der überarbeitetet COde:

      var ImageName, ImageNumber, ImageNumberConverted, NewLink;
      
      on({id: "daswetter.0.NextHours.Location_1.Day_1.current.iconURL", change: "any"}, async function (obj) {
        // Sicherstellen, dass obj.state und obj.state.val existieren
        if (!obj.state || typeof obj.state.val === 'undefined') {
          console.error("obj.state.val ist undefined!");
          return; // Früher zurückkehren, wenn der Wert nicht definiert ist
        }
      
        var value = obj.state.val;
        var oldValue = obj.oldState.val;
        
        // Extrahiert den ImageNumber aus der URL
        ImageName = (obj.state ? obj.state.val : "").split('/');
        
        // Sicherstellen, dass ImageName genügend Teile hat
        if (ImageName.length > 6) {
          ImageNumber = ImageName[6]; // Greife auf den 7. Teil der URL zu (Index 6)
        } else {
          console.error("Die URL hat nicht genügend Teile. ImageName:", ImageName);
          return; // Rückgabe, wenn die URL nicht das erwartete Format hat
        }
      
        // Überprüfet, ob ImageNumber existiert und berechnet ImageNumberConverted
        if (ImageNumber) {
          ImageNumberConverted = parseFloat(ImageNumber.slice(0, ImageNumber.length - 4));
        } else {
          console.error("ImageNumber ist undefined");
          return; // Früher zurückkehren, wenn ImageNumber nicht definiert ist
        }
      
        // Berechnet die Zeit für Sonnenaufgang und Sonnenuntergang
        var sunrise = getDateObject(getAstroDate("sunrise", undefined, 0));
        var sunrise_m = sunrise.getHours() * 60 + sunrise.getMinutes();
        var sunset = getDateObject(getAstroDate("sunset", undefined, 0));
        var sunset_m = sunset.getHours() * 60 + sunset.getMinutes();
        var now = new Date();
        var now_m = now.getHours() * 60 + now.getMinutes();
      
        // Setzt den Wert für die Animation
        setState("0_userdata.0.Wetter.WeatherAnimation.WeatherAnimation", ImageNumberConverted);
      
        // Logik für unterschiedliche Tageszeiten
        if (now_m > sunset_m - 60 && now_m <= sunset_m + 60) {
          log("dusk " + sunrise_m + " " + sunset_m);
          setState("0_userdata.0.Wetter.WeatherAnimation.Weatherurl", obj.state.val, true);
        } else if (now_m > sunrise_m - 60 && now_m <= sunrise_m + 60) {
          log("dawn " + sunrise_m + " " + sunset_m);
          NewLink = ['http://192.168.178.70:8082/vis.0/Wetter/WeatherAnimation/', ImageNumberConverted + 50, '.png'].join('');
          setState("0_userdata.0.Wetter.WeatherAnimation.Weatherurl", NewLink, true);
        } else if (now_m > sunrise_m + 60 && now_m <= sunset_m - 60) {
          log("day " + sunrise_m + " " + sunset_m);
          setState("0_userdata.0.Wetter.WeatherAnimation.Weatherurl", obj.state.val, true);
        } else {
          log("night " + sunrise_m + " " + sunset_m);
          NewLink = ['http://192.168.178.70:8082/vis.0/Wetter/WeatherAnimation/', ImageNumberConverted + 50, '.png'].join('');
          setState("0_userdata.0.Wetter.WeatherAnimation.Weatherurl", NewLink, true);
        }
      
        // Konsolenausgaben für Debugging
        console.log("ImageName:", ImageName);
        console.log("ImageNumber:", ImageNumber);
        console.log("ImageNumberConverted:", ImageNumberConverted);
        console.log("sunrise_m:", sunrise_m);
        console.log("sunset_m:", sunset_m);
        console.log("now_m:", now_m);
      });
      

      Ich habe folgenden DAtenpunkte angelegt:

      0_userdata.0.Wetter.WeatherAnimation.WeatherAnimation
      0_userdata.0.Wetter.WeatherAnimation.Weatherurl
      

      Der DAtenpunkt Animation wird befüllt mit einer Zahl, auch die WeatherURL. Aber ich erhalte dann eine z.B. Animation 2 und url http://192.168.178.70:8082/vis.0/Wetter/WeatherAnimation/52.png

      In der VIS wird dann logischerweise auch nicht das richtige Bild angezeigt. Kann mir jemand bitte helfen?

      edit:
      Ich habe den Code wie folgt abgeändert:

      var ImageName, ImageNumber, ImageNumberConverted, NewLink;
      
      on({id: "daswetter.0.NextHours.Location_1.Day_1.current.iconURL", change: "any"}, async function (obj) {
        // Sicherstellen, dass obj.state und obj.state.val existieren
        if (!obj.state || typeof obj.state.val === 'undefined') {
          console.error("obj.state.val ist undefined!");
          return; // Früher zurückkehren, wenn der Wert nicht definiert ist
        }
      
        var value = obj.state.val;
        var oldValue = obj.oldState.val;
        
        // Ausgabe der URL, um zu sehen, wie sie aussieht
        console.log("URL:", value);
        
        // Falls die URL leer oder ungültig ist, logge eine Fehlermeldung
        if (!value) {
          console.error("Die URL (obj.state.val) ist leer oder ungültig!");
          return;
        }
        
        // Extrahiere den ImageNumber aus der URL
        ImageName = value.split('/');
        console.log("ImageName Teile:", ImageName); // Ausgabe der Teile nach dem Split
      
        // Versuchen, den Dateinamen zu extrahieren
        if (ImageName.length > 0) {
          // Der Dateiname könnte der letzte Teil der URL sein
          const filename = ImageName[ImageName.length - 1];
          console.log("Dateiname:", filename);
      
          // Versuchen, die Bildnummer aus dem Dateinamen zu extrahieren
          const match = filename.match(/^(\d+)\.png$/); // Annahme: Der Dateiname ist eine Zahl gefolgt von .png
          if (match) {
            ImageNumber = match[1];
            ImageNumberConverted = parseFloat(ImageNumber);
            console.log("Extrahierte Bildnummer:", ImageNumber);
          } else {
            console.error("Kein gültiger Dateiname gefunden");
            return;
          }
        } else {
          console.error("Die URL hat nicht genügend Teile.");
          return; // Rückgabe, wenn die URL nicht das erwartete Format hat
        }
      
        // Berechne die Zeit für Sonnenaufgang und Sonnenuntergang
        var sunrise = getDateObject(getAstroDate("sunrise", undefined, 0));
        var sunrise_m = sunrise.getHours() * 60 + sunrise.getMinutes();
        var sunset = getDateObject(getAstroDate("sunset", undefined, 0));
        var sunset_m = sunset.getHours() * 60 + sunset.getMinutes();
        var now = new Date();
        var now_m = now.getHours() * 60 + now.getMinutes();
      
        // Setze den Wert für die Animation
        setState("0_userdata.0.Wetter.WeatherAnimation.WeatherAnimation", ImageNumberConverted);
      
        // Logik für unterschiedliche Tageszeiten
        if (now_m > sunset_m - 60 && now_m <= sunset_m + 60) {
          log("dusk " + sunrise_m + " " + sunset_m);
          setState("0_userdata.0.Wetter.WeatherAnimation.Weatherurl", obj.state.val, true);
        } else if (now_m > sunrise_m - 60 && now_m <= sunrise_m + 60) {
          log("dawn " + sunrise_m + " " + sunset_m);
          NewLink = ['http://192.168.178.70:8082/vis.0/Wetter/WeatherAnimation/', ImageNumberConverted + 50, '.png'].join('');
          setState("0_userdata.0.Wetter.WeatherAnimation.Weatherurl", NewLink, true);
        } else if (now_m > sunrise_m + 60 && now_m <= sunset_m - 60) {
          log("day " + sunrise_m + " " + sunset_m);
          setState("0_userdata.0.Wetter.WeatherAnimation.Weatherurl", obj.state.val, true);
        } else {
          log("night " + sunrise_m + " " + sunset_m);
          NewLink = ['http://192.168.178.70:8082/vis.0/Wetter/WeatherAnimation/', ImageNumberConverted + 50, '.png'].join('');
          setState("0_userdata.0.Wetter.WeatherAnimation.Weatherurl", NewLink, true);
        }
      
        // Konsolenausgaben für Debugging
        //console.log("ImageName:", ImageName);
        //console.log("ImageNumber:", ImageNumber);
        //console.log("ImageNumberConverted:", ImageNumberConverted);
        //console.log("sunrise_m:", sunrise_m);
        //console.log("sunset_m:", sunset_m);
        //console.log("now_m:", now_m);
      });
      
      

      Jetzt bekomme ich in

      0_userdata.0.Wetter.WeatherAnimation.Weatherurl = /vis.0/main/Wetter/Wetter Hd/2.png
      

      und

      0_userdata.0.Wetter.WeatherAnimation.WeatherAnimation = 2
      

      Außerdem erhalte ich noch folgenden Fehler, den ich schon einmal hatte:

      web.0
      2025-03-25 16:37:01.785	error	Invalid pattern on subscribe: The pattern "id: "daswetter.0.NextHours.Location_1.Day_1.current.iconURL", change: "any"" is not a valid ID pattern
      
      posted in Visualisierung
      J
      jwerlsdf
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
    The ioBroker Community 2014-2023
    logo