Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. Light-Mode / Dark-Mode

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    Light-Mode / Dark-Mode

    This topic has been deleted. Only users with topic management privileges can see it.
    • M
      Mr_Sans last edited by

      Hallo Zusammen

      Ich habe mich in den letzten Tag ein wenig mit dem automatischen switch von Light-Mode zu Dark-Mode beschäftigt.
      Würde gerne mein Stand mit euch Teilen und freue mich über Anregungen oder Verbesserungen.

      Ich nutze vorwiegend @Scrounger Material Design Widgets.

      Als erstes habe ich mir im JS-Adapter ein Script erstellt, welches anhand der Tageszeit ein Datenpunkt befüllt

      
      // imports NPM Module
      const moment = require("moment");
      moment.locale("de");
      
      // Skript Einstellungen *************************************************************************************************************************************************
      let debug = true;                                                                                           // Debug Meldungen anzeigen
      let strukturChannel = '0_userdata.0.vis.Scripts.Control';                                                      // Übergeordnete Id, wo die Datenpunkte angelegt werden sollen
       
      let idColorDatenpunkt = `${strukturChannel}.datapoint_color`    
      
      createControlDatapoints();
      
      schedule({hour: 08, minute: 00}, lightmode );
      schedule({hour: 19, minute: 30}, darkmode ); 
      
       function darkmode() {
         setState(idColorDatenpunkt, 'darkmode');
       }
       
       function lightmode() {
         setState(idColorDatenpunkt, 'lightmode');
       }
      
      
      
      function createControlDatapoints() {
          if (!existsState(idColorDatenpunkt)) {
              if (debug) console.debug(`[createControlDatapoints]: create datapoint '${idColorDatenpunkt}'`);
              mySetState(idColorDatenpunkt, 'lightmode', 'string', `Light or Dark Mode`);
          }
      }
      
      function mySetState(id, val, type, name) {
          if (existsState(id)) {
              if (debug) console.debug(`[mySetState]: history colore data stored to '${id}'`);
              setState(id, val, true);
          } else {
              if (debug) console.debug(`[mySetState]: create datapoint '${id}'`);
              createUserStates(false, [
                  id, {
                      'name': name,
                      'type': type,
                      'read': true,
                      'write': true
                  }
              ], function () {
                  setState(id, val, true);
              });
          }
      }
      /**
       * Create states under 0_userdata.0 or javascript.x
       * Current Version:     https://github.com/Mic-M/iobroker.createUserStates
       * Support:             https://forum.iobroker.net/topic/26839/
       * Autor:               Mic (ioBroker) | Mic-M (github)
       * Version:             1.1 (26 January 2020)
       * Example:             see https://github.com/Mic-M/iobroker.createUserStates#beispiel
       * -----------------------------------------------
       * PLEASE NOTE: Per https://github.com/ioBroker/ioBroker.javascript/issues/474, the used function setObject() 
       *              executes the callback PRIOR to completing the state creation. Therefore, we use a setTimeout and counter. 
       * -----------------------------------------------
       * @param {boolean} force         Force state creation (overwrite), if state is existing.
       * @param {array} statesToCreate  State(s) to create. single array or array of arrays
       * @param {object} [callback]     Optional: a callback function -- This provided function will be executed after all states are created.
       */
      function createUserStates(force, statesToCreate, callback = undefined) {
          const where = '0_userdata.0'
       
          const WARN = false; // Only for 0_userdata.0: Throws warning in log, if state is already existing and force=false. Default is false, so no warning in log, if state exists.
          const LOG_DEBUG = false; // To debug this function, set to true
          // Per issue #474 (https://github.com/ioBroker/ioBroker.javascript/issues/474), the used function setObject() executes the callback 
          // before the state is actual created. Therefore, we use a setTimeout and counter as a workaround.
          const DELAY = 50; // Delay in milliseconds (ms). Increase this to 100, if it is not working.
       
          // Validate "where"
          if (where.endsWith('.')) where = where.slice(0, -1); // Remove trailing dot
          if ((where.match(/^((javascript\.([1-9][0-9]|[0-9]))$|0_userdata\.0$)/) == null)) {
              log('This script does not support to create states under [' + where + ']', 'error');
              return;
          }
       
          // Prepare "statesToCreate" since we also allow a single state to create
          if (!Array.isArray(statesToCreate[0])) statesToCreate = [statesToCreate]; // wrap into array, if just one array and not inside an array
       
          // Add "where" to STATES_TO_CREATE
          for (let i = 0; i < statesToCreate.length; i++) {
              let lpPath = statesToCreate[i][0].replace(/\.*\./g, '.'); // replace all multiple dots like '..', '...' with a single '.'
              lpPath = lpPath.replace(/^((javascript\.([1-9][0-9]|[0-9])\.)|0_userdata\.0\.)/, '') // remove any javascript.x. / 0_userdata.0. from beginning
              lpPath = where + '.' + lpPath; // add where to beginning of string
              statesToCreate[i][0] = lpPath;
          }
       
          if (where != '0_userdata.0') {
              // Create States under javascript.x
              let numStates = statesToCreate.length;
              statesToCreate.forEach(function (loopParam) {
                  if (LOG_DEBUG) log('[Debug] Now we are creating new state [' + loopParam[0] + ']');
                  let loopInit = (loopParam[1]['def'] == undefined) ? null : loopParam[1]['def']; // mimic same behavior as createState if no init value is provided
                  createState(loopParam[0], loopInit, force, loopParam[1], function () {
                      numStates--;
                      if (numStates === 0) {
                          if (LOG_DEBUG) log('[Debug] All states processed.');
                          if (typeof callback === 'function') { // execute if a function was provided to parameter callback
                              if (LOG_DEBUG) log('[Debug] Function to callback parameter was provided');
                              return callback();
                          } else {
                              return;
                          }
                      }
                  });
              });
          } else {
              // Create States under 0_userdata.0
              let numStates = statesToCreate.length;
              let counter = -1;
              statesToCreate.forEach(function (loopParam) {
                  counter += 1;
                  if (LOG_DEBUG) log('[Debug] Currently processing following state: [' + loopParam[0] + ']');
                  if (($(loopParam[0]).length > 0) && (existsState(loopParam[0]))) { // Workaround due to https://github.com/ioBroker/ioBroker.javascript/issues/478
                      // State is existing.
                      if (WARN && !force) log('State [' + loopParam[0] + '] is already existing and will no longer be created.', 'warn');
                      if (!WARN && LOG_DEBUG) log('[Debug] State [' + loopParam[0] + '] is already existing. Option force (=overwrite) is set to [' + force + '].');
                      if (!force) {
                          // State exists and shall not be overwritten since force=false
                          // So, we do not proceed.
                          numStates--;
                          if (numStates === 0) {
                              if (LOG_DEBUG) log('[Debug] All states successfully processed!');
                              if (typeof callback === 'function') { // execute if a function was provided to parameter callback
                                  if (LOG_DEBUG) log('[Debug] An optional callback function was provided, which we are going to execute now.');
                                  return callback();
                              }
                          } else {
                              // We need to go out and continue with next element in loop.
                              return; // https://stackoverflow.com/questions/18452920/continue-in-cursor-foreach
                          }
                      } // if(!force)
                  }
       
                  // State is not existing or force = true, so we are continuing to create the state through setObject().
                  let obj = {};
                  obj.type = 'state';
                  obj.native = {};
                  obj.common = loopParam[1];
                  setObject(loopParam[0], obj, function (err) {
                      if (err) {
                          log('Cannot write object for state [' + loopParam[0] + ']: ' + err);
                      } else {
                          if (LOG_DEBUG) log('[Debug] Now we are creating new state [' + loopParam[0] + ']')
                          let init = null;
                          if (loopParam[1].def === undefined) {
                              if (loopParam[1].type === 'number') init = 0;
                              if (loopParam[1].type === 'boolean') init = false;
                              if (loopParam[1].type === 'string') init = '';
                          } else {
                              init = loopParam[1].def;
                          }
                          setTimeout(function () {
                              setState(loopParam[0], init, true, function () {
                                  if (LOG_DEBUG) log('[Debug] setState durchgeführt: ' + loopParam[0]);
                                  numStates--;
                                  if (numStates === 0) {
                                      if (LOG_DEBUG) log('[Debug] All states processed.');
                                      if (typeof callback === 'function') { // execute if a function was provided to parameter callback
                                          if (LOG_DEBUG) log('[Debug] Function to callback parameter was provided');
                                          return callback();
                                      }
                                  }
                              });
                          }, DELAY + (20 * counter));
                      }
                  });
              });
          }
      }
      

      Dieser Datenpunkt wird verwendet um z.B den Zustand auch den Charts übergeben zu können, da diese nicht vollständig übers CSS angepasst werden können. Im Editor hab ich folgendes hinterlegt:

      {wert:0_userdata.0.vis.Scripts.Control.datapoint_color;(wert =="lightmode") ? "#505050" : (wert =="darkmode") ? "#ffffff" : "#ffffff"}
      

      Da leider der JS-Adapter nicht direkt auf das CSS zugreifen kann, nutze ich das Register Skript im Editor für einen zusätzlichen Workaround:

      vis.registerOnChange(status_callback);
       
      vis.subscribing.IDs.push("0_userdata.0.vis.Scripts.Control.datapoint_color");
      
      function status_callback(arg, id, val, ack)
      {
          if (val=="lightmode")
          	document.documentElement.setAttribute('data-theme', 'light');
      			localStorage.setItem('theme', 'light');
          if (val=="darkmode") 
          	document.documentElement.setAttribute('data-theme', 'dark');
      			localStorage.setItem('theme', 'dark');
          
          console.log('Status', 'Id:' + id+', Val:'+val);
      }
      
      let objID = '0_userdata.0.vis.Scripts.Control.datapoint_color';
      servConn.getStates(objID, (error, states) => {
          let stateValue = states[objID].val;
              if (stateValue=="lightmode")
          	document.documentElement.setAttribute('data-theme', 'light');
      			localStorage.setItem('theme', 'light');
          if (stateValue=="darkmode") 
          	document.documentElement.setAttribute('data-theme', 'dark');
      			localStorage.setItem('theme', 'dark');
          
          console.log('Status', 'Id:' + id+', Val:'+val);
      });
      

      Das CSS sieht wie folgt aus:

      /* Design-time light-Theme */
      :root[data-theme="light"] {
        --main-background: #ffffff;
        --content-background: #f5f5f5;
        --content-background-hover: #505050;
        --design-font-color: #505050;
        --design-font-color-hover: #ffffff;
        --design-fontsize : 0.9em;
        --filter-svg:;
        --filter-svg-hover: brightness(0) invert(1);
        --border-color: #e0e0e0; 
      } 
      /* Design-time dark-Theme */
      :root[data-theme="dark"] {
        --main-background: #000000;
        --content-background: #505050;
        --content-background-hover: #808080;
        --design-font-color: #ffffff;
        --design-font-color-hover: #505050;
        --design-fontsize : 0.9em;
        --filter-svg: brightness(0) invert(1);
        --filter-svg-hover: ;
        --border-color: #404040; 
      }
      

      Ich habe den grössten Teil Design-Teil im CSS und mache nur das nötigste im Editor (dies vorallem, da ich aktuell auf Rund 180 Seiten bin und bei kleinen Änderungen nicht alle Seiten öffnen möchte für Anpassungen.
      Bei mir Funktioniert dies wunderbar.

      Hier mal noch ein grosses Lob an @Scrounger und seine Widgets --> Hammer!!

      Viel spass beim ausprobieren und für allfällige Feedbacks...

      Mic-M created this issue in ioBroker/ioBroker.javascript

      closed setObject() function: callback not working as intended. #474

      Mic-M created this issue in ioBroker/ioBroker.javascript

      closed setObject() function: callback not working as intended. #474

      Mic-M created this issue in ioBroker/ioBroker.javascript

      closed 0_userdata.0: existsState() vs. $-Selector $().length after state deletion #478

      ice987 1 Reply Last reply Reply Quote 0
      • ice987
        ice987 @Mr_Sans last edited by ice987

        @mr_sans

        coole Geschichte! Der Mode wird aktuell gemäss einer fixen Zeit aus dem schedule erstellt. Eine Idee wäre auch, den Status des "dark modes" direkt aus dem Browser auszulesen, was meinst du?

        1 Reply Last reply Reply Quote 0
        • First post
          Last post

        Support us

        ioBroker
        Community Adapters
        Donate

        534
        Online

        31.8k
        Users

        80.0k
        Topics

        1.3m
        Posts

        javascript template
        2
        2
        1569
        Loading More Posts
        • Oldest to Newest
        • Newest to Oldest
        • Most Votes
        Reply
        • Reply as topic
        Log in to reply
        Community
        Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
        The ioBroker Community 2014-2023
        logo