Ankündigung

Einklappen
Keine Ankündigung bisher.

Zeitschaltuhr / crontab in der VISU ?

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Zeitschaltuhr / crontab in der VISU ?

    Hallo,

    was haltet Ihr von folgendem:
    - ein Schalter item als Zeitschaltuhr läßt sich über die VISU einstellen
    - in der VISU stelle ich die Felder für zwei crontabs für den Ein- und Ausschaltzeitpunkt ein
    - über eine Logic modifiziere ich dann die crontab des item

    Könnte etwa so aussehen:

    im Item ein Unter-Item für die Zeitschaltuhr hinzufügen. Dieses verwaltet den CronTab String:
    Code:
    [aussen]
        [[vorn]]
            [[[licht2]]]
                name = Außenbeleuchtung
                type = bool
                visu_acl = rw
                sv_widget = "{{ basic.switch('item', 'item') }}<br>{{ basic.value('item_cron', 'item.zeitschaltuhr') }}"
                knx_dpt = 1
                knx_send = 0/0/21
                knx_init = 0/1/21
                enforce_update = yes
    	    crontab = 0 17 * * = 1 | 0 7 * * = 0
    		[[[[zeitschaltuhr]]]]
    			name = Zeitschaltuhr
    			type = foo
    			visu_acl = rw
    			sv_widget = "{{ basic.crontab('item', 'item') }} "
    		        enforce_update = yes
    und die Logic, die die crontab ändert:
    Code:
    [zeitschaltuhr]
    	filename = zeitschaltuhr.py
    	visu_acl = yes
    file logics/zeitschaltuhr.py
    Code:
    #!/usr/bin/env python
    #
    
    logger.info("Zeitschaltuhr Value :" + trigger['value'] )
    
    item_id = trigger['value']
    item = sh.return_item(item_id)
    
    if item is not None :
    	new_crontab = item()
    
    	
    	new_crontab = new_crontab.replace("_", " ").strip()
    	
    	logger.info("Zeitschaltuhr EIN/AUS :" + new_crontab )
    
    	item = item.return_parent()
    	sh.scheduler.change(item.id(), cron=new_crontab)
    	
    
    else:
    	logger.info("Zeitschaltuhr ungueltig!")
    Damit das funktioniert, muss der scheculer.py wie unten gepatched werden.

    das Widget geht sicher eleganter (Hilfe erwünscht!):
    Code:
    /**
    * Displays a crontab Zeitschaltuhr
    *
    * @param unique id for this widget
    * @param a gad/item
    * @param text printed on the checkbox
    */
    {% macro crontab(id, gad) %}
        <div id="{{ uid(page, id) }}" data-widget="basic.crontab" data-item="{{ gad }}" value="{{ gad }}">
    
    	<label for="{{ uid(page, id) }}_wday_1" class="select">Einschalten jeden:</label>
    	<fieldset data-role="controlgroup" data-type="horizontal" data-mini="true">
    	<select id="{{ uid(page, id) }}_wday_1" data-native-menu="false" multiple>
    		<option data-placeholder="true">Tag</option>
    		<option value="0">Montag</option>
    		<option value="1">Dienstag</option>
    		<option value="2">Mittwoch</option>
    		<option value="3">Donnerstag</option>
    		<option value="4">Freitag</option>
    		<option value="5">Samstag</option>
    		<option value="6">Sonntag</option>
    	</select>		
    	<select id="{{ uid(page, id) }}_hour_1" data-native-menu="false" multiple>
    		<option data-placeholder="true">Stunde</option>
    		<option value="0" >00 Uhr</option><option value="1" >01 Uhr</option><option value="2" >02 Uhr</option><option value="3" >03 Uhr</option><option value="4" >04 Uhr</option>		
    		<option value="5" >05 Uhr</option><option value="6" >06 Uhr</option><option value="7" >07 Uhr</option><option value="8" >08 Uhr</option><option value="9" >09 Uhr</option>		
    		<option value="10">10 Uhr</option><option value="11">11 Uhr</option><option value="12" >12 Uhr</option><option value="13" >13 Uhr</option><option value="14" >14 Uhr</option>		
    		<option value="15">15 Uhr</option><option value="16">16 Uhr</option><option value="17" >17 Uhr</option><option value="18" >18 Uhr</option><option value="19" >19 Uhr</option>		
    		<option value="20">20 Uhr</option><option value="21">21 Uhr</option><option value="22" >22 Uhr</option><option value="23" >23 Uhr</option>		
    	</select>		
    	<select id="{{ uid(page, id) }}_mins_1" data-native-menu="false" multiple>
    		<option data-placeholder="true">Minute</option>
    		<option value="0" >00</option><option value="0" >05</option>		
    		<option value="10">10</option><option value="15">15</option>		
    		<option value="20">20</option><option value="25">25</option>		
    		<option value="30">30</option><option value="35">35</option>		
    		<option value="40">40</option><option value="45">45</option>		
    		<option value="50">50</option><option value="55">55</option>
    	</select>		
    	</fieldset>
    
    	<label for="{{ uid(page, id) }}_wday_0" class="select">Ausschalten jeden:</label>
    	<fieldset data-role="controlgroup" data-type="horizontal" data-mini="true">
    	<select id="{{ uid(page, id) }}_wday_0" data-native-menu="false" multiple>
    		<option data-placeholder="true">Tag</option>
    		<option value="0">Montag</option>
    		<option value="1">Dienstag</option>
    		<option value="2">Mittwoch</option>
    		<option value="3">Donnerstag</option>
    		<option value="4">Freitag</option>
    		<option value="5">Samstag</option>
    		<option value="6">Sonntag</option>
    	</select>		
    	<select id="{{ uid(page, id) }}_hour_0" data-native-menu="false" multiple>
    		<option data-placeholder="true">Stunde</option>
    		<option value="0" >00 Uhr</option><option value="1" >01 Uhr</option><option value="2" >02 Uhr</option><option value="3" >03 Uhr</option><option value="4" >04 Uhr</option>		
    		<option value="5" >05 Uhr</option><option value="6" >06 Uhr</option><option value="7" >07 Uhr</option><option value="8" >08 Uhr</option><option value="9" >09 Uhr</option>		
    		<option value="10">10 Uhr</option><option value="11">11 Uhr</option><option value="12" >12 Uhr</option><option value="13" >13 Uhr</option><option value="14" >14 Uhr</option>		
    		<option value="15">15 Uhr</option><option value="16">16 Uhr</option><option value="17" >17 Uhr</option><option value="18" >18 Uhr</option><option value="19" >19 Uhr</option>		
    		<option value="20">20 Uhr</option><option value="21">21 Uhr</option><option value="22" >22 Uhr</option><option value="23" >23 Uhr</option>		
    	</select>		
    	<select id="{{ uid(page, id) }}_mins_0" data-native-menu="false" multiple>
    		<option data-placeholder="true">Minute</option>
    		<option value="0" >00</option><option value="0" >05</option>		
    		<option value="10">10</option><option value="15">15</option>		
    		<option value="20">20</option><option value="25">25</option>		
    		<option value="30">30</option><option value="35">35</option>		
    		<option value="40">40</option><option value="45">45</option>		
    		<option value="50">50</option><option value="55">55</option>
    	</select>		
    	</fieldset>
        </div>
    
       <a id="{{ uid(page, id) }}_set" data-widget="basic.crontab_set" data-name="zeitschaltuhr" data-val="{{ id }}"
    		class="ui-midi" data-role="button" data-inline="true" data-iconpos="nopic">
    	<div>set</div>
       </a>
    
    {% endmacro %}
    Widget JavaScript: UPDATE 08.12. 15:30h: init und update functions
    Code:
    // ----- c r o n t a b ------------------------------------------------------------
    // ----------------------------------------------------------------------------
    
    // ----- basic.crontab -------------------------------------------------------
    $(document).delegate('div[data-widget="basic.crontab"]', {
        'init': function (event) {
    	 	//* 'init' : Triggered from the widget (macro) itself to change it dynamically on startup.
    		this.update(event, $(this).attr('data-val') );
        },
    
    	'update': function (event, response) {
    	 	//* 'udate': Triggered through widget.update if a item has been changed.
    	 	// DEBUG: 
    	 	console.log("[basic.crontab] update response :" + response[0] ); 
    		cr = response[0].split(' | ');
    	 	// DEBUG: console.log("[basic.crontab] update split cr :" + cr ); 
    		cr1 = cr[0].split(' =')[0].split('_');
    		cr0 = cr[1].split(' =')[0].split('_');
    	 	// DEBUG: console.log("[basic.crontab] update cr1, cr0 :" + cr1 + " , " +cr0 ); 
    		mins_1 = cr1[0].split(','); mins_0 = cr0[0].split(',');
    		hour_1 = cr1[1].split(','); hour_0 = cr0[1].split(',');
    		wday_1 = cr1[2].split(','); wday_0 = cr0[2].split(',');
    	 	// DEBUG: console.log("[basic.crontab] update crontab EIN: m"+mins_1+" h"+hour_1+" d"+wday_1); 
    	 	console.log("[basic.crontab] update crontab AUS: m"+mins_0+" h"+hour_0+" d"+wday_0); 
    		
    		if (mins_1 != "*") { $('#' + this.id + '_mins_1').val(mins_1)}; $('#' + this.id + '_mins_1').selectmenu('refresh', true);
    		if (hour_1 != "*") { $('#' + this.id + '_hour_1').val(hour_1)};	$('#' + this.id + '_hour_1').selectmenu('refresh', true);
    		if (wday_1 != "*") { $('#' + this.id + '_wday_1').val(wday_1)};	$('#' + this.id + '_wday_1').selectmenu('refresh', true);
    		
    		if (mins_0 != "*") { $('#' + this.id + '_mins_0').val(mins_0)}; $('#' + this.id + '_mins_0').selectmenu('refresh', true);
    		if (hour_0 != "*") { $('#' + this.id + '_hour_0').val(hour_0)};	$('#' + this.id + '_hour_0').selectmenu('refresh', true);
    		if (wday_0 != "*") { $('#' + this.id + '_wday_0').val(wday_0)};	$('#' + this.id + '_wday_0').selectmenu('refresh', true);
    
    	},
    
    	'change': function (event) {
    		//* Standard jquery-mobile events, triggered from the framework.
    		var wday_1 = $('#' + this.id + '_wday_1').val(); wday_1 = (wday_1) ? wday_1 : "*";
    		var hour_1 = $('#' + this.id + '_hour_1').val(); hour_1 = (hour_1) ? hour_1 : "*";
    		var mins_1 = $('#' + this.id + '_mins_1').val(); mins_1 = (mins_1) ? mins_1 : "*";
    		// DEBUG: console.log("[basic.crontab] EIN change '" + this.id + "':" + wday_1 + ":" + hour_1 + ":" + mins_1 ); 
    		
    		var wday_0 = $('#' + this.id + '_wday_0').val(); wday_0 = (wday_0) ? wday_0 : "*";
    		var hour_0 = $('#' + this.id + '_hour_0').val(); hour_0 = (hour_0) ? hour_0 : "*";
    		var mins_0 = $('#' + this.id + '_mins_0').val(); mins_0 = (mins_0) ? mins_0 : "*";
    		// DEBUG: console.log("[basic.crontab] AUS change '" + this.id + "':" + wday_0 + ":" + hour_0 + ":" + mins_0 ); 
    		
    		var crontab_1 = mins_1 + "_" + hour_1 + "_" + wday_1 + '_*';
    		var crontab_0 = mins_0 + "_" + hour_0 + "_" + wday_0 + '_*';
    		
    		io.write($(this).attr('data-item'), crontab_1 + ' = 1 | ' + crontab_0 + " = 0" );
    	}
    });
    
    $(document).delegate('a[data-widget="basic.crontab_set"]', {
    	'click': function (event) {
    		io.trigger($(this).attr('data-name'), $(this).attr('data-val'));
    	}
    });
    Angehängte Dateien

    #2
    leider scheitere ich an dieser Stelle:
    Code:
    2013-12-07 23:54:42,874 DEBUG    Main         Triggering zeitschaltuhr - by: Visu source: 192.168.178.23:57646 dest: None value: aussen.vorn.licht2.zeitschaltuhr -- scheduler.py:trigger:162
    2013-12-07 23:54:42,880 INFO     zeitschaltuhr Zeitschaltuhr Value :aussen.vorn.licht2.zeitschaltuhr -- zeitschaltuhr.py:<module>:4
    2013-12-07 23:54:42,885 INFO     zeitschaltuhr Zeitschaltuhr EIN/AUS :* * 1 * = 1 | 25 * * * = 0 -- zeitschaltuhr.py:<module>:15
    2013-12-07 23:54:42,891 DEBUG    zeitschaltuhr ................job[cron]:['* * 1 * = 1 ', ' 25 * * * = 0'] -- scheduler.py:_next_time:278
    2013-12-07 23:54:42,896 ERROR    zeitschaltuhr Error parsing crontab: * * 1 * = 1  -- scheduler.py:_crontab:364
    2013-12-07 23:54:42,913 ERROR    zeitschaltuhr Logic: zeitschaltuhr, File: /usr/smarthome/lib/scheduler.py, Line: 287, Method: _next_time, Exception: list indices must be integers, not str -- scheduler.py:_task:336
    Traceback (most recent call last):
      File "/usr/smarthome/lib/scheduler.py", line 329, in _task
        exec(obj.bytecode)
      File "/usr/smarthome/logics/zeitschaltuhr.py", line 18, in <module>
        sh.scheduler.change(item.id(), cron=new_crontab)
      File "/usr/smarthome/lib/scheduler.py", line 255, in change
        self._next_time(name)
      File "/usr/smarthome/lib/scheduler.py", line 287, in _next_time
        value = job['cron'][entry]
    TypeError: list indices must be integers, not str
    an dieser Stelle habe ich geDEBUGt:
    Code:
        def _next_time(self, name, offset=None):
            job = self._scheduler[name]        
            if None == job['cron'] == job['cycle']:
                self._scheduler[name]['next'] = None
                return
            next_time = None
            value = None
            now = self._sh.now()
            now = now.replace(microsecond=0)
            if job['cycle'] is not None:
                cycle = list(job['cycle'].keys())[0]
                value = job['cycle'][cycle]
                if offset is None:
                    offset = cycle
                next_time = now + datetime.timedelta(seconds=offset)
            if job['cron'] is not None:
                logger.debug("................job[cron]:{0}".format(job['cron']))
                for entry in job['cron']:
                    ct = self._crontab(entry)
                    if next_time is not None:
                        if ct < next_time:
                            next_time = ct
                            value = job['cron'][entry]
                    else:
                        next_time = ct
                        value = job['cron'][entry]
            self._scheduler[name]['next'] = next_time
            self._scheduler[name]['value'] = value
            if name not in ['Connections', 'series', 'SQLite dump']:
                logger.debug("{0} next time: {1}".format(name, next_time))
    offenbar sollte job['cron'] hier ein dict sein, ist aber ein list?!?

    Gruß, Dirk

    Kommentar


      #3
      scheduler gepatched

      ich habe das jetzt mal so gefixed:

      Code:
          def change(self, name, **kwargs):
              if name in self._scheduler:
                  for key in kwargs:
                      if key in self._scheduler[name]:
                          if key == 'cron':
                              if isinstance(kwargs[key], str):
      
                                  _cron = {}
                                  for entry in kwargs[key].split('|'):
                                      desc, __, _value = entry.partition('=')
                                      desc = desc.strip()
                                      if _value == '':
                                          _value = None
                                      else:
                                          _value = _value.strip()
                                      _cron[desc] = _value
                                  if _cron == {}:
                                      kwargs[key] = None
                                  else:
                                      kwargs[key] = _cron
                                  
      
                          elif key == 'active':
                              if kwargs['active'] and not self._scheduler[name]['active']:
                                  logger.info("Activating logic: {0}".format(name))
                              elif not kwargs['active'] and self._scheduler[name]['active']:
                                  logger.info("Deactivating logic: {0}".format(name))
                          self._scheduler[name][key] = kwargs[key]
                      else:
                          logger.warning("Attribute {0} for {1} not specified. Could not change it.".format(key, name))
                  if self._scheduler[name]['active'] is True:
                      if 'cycle' in kwargs or 'cron' in kwargs:
                          self._next_time(name)
                  else:
                      self._scheduler[name]['next'] = None
              else:
                  logger.warning("Could not change {0}. No logic/method with this name found.".format(name))
      Scheint jetzt zu funktionieren!!!

      Code:
      2013-12-08 01:02:53,844 DEBUG    Main         Triggering zeitschaltuhr - by: Visu source: 192.168.178.23:57689 dest: None value: aussen.vorn.licht2.zeitschaltuhr -- scheduler.py:trigger:162
      2013-12-08 01:02:53,850 INFO     zeitschaltuhr Zeitschaltuhr Value :aussen.vorn.licht2.zeitschaltuhr -- zeitschaltuhr.py:<module>:4
      2013-12-08 01:02:53,855 INFO     zeitschaltuhr Zeitschaltuhr EIN/AUS :0,10,20,30,40,50 * * * = 1 | 0,15,25,35,45,55 * * * = 0 -- zeitschaltuhr.py:<module>:15
      2013-12-08 01:02:53,861 DEBUG    zeitschaltuhr ................job[cron]:{'0,15,25,35,45,55 * * *': '0', '0,10,20,30,40,50 * * *': '1'} -- scheduler.py:_next_time:293
      2013-12-08 01:02:54,049 DEBUG    zeitschaltuhr aussen.vorn.licht2 next time: 2013-12-08 01:10:00+01:00 -- scheduler.py:_next_time:306
      
      
      2013-12-08 01:06:11,387 DEBUG    env_stat     Item env.core.memory = 14909440 via Logic None None -- item.py:__update:363
      2013-12-08 01:06:11,836 DEBUG    Scheduler    env_stat next time: 2013-12-08 01:11:11+01:00 -- scheduler.py:_next_time:306
      
      2013-12-08 01:10:00,410 DEBUG    aussen.vorn.licht2 Item aussen.vorn.licht2 = True via Scheduler None None -- item.py:__update:363
      2013-12-08 01:10:00,918 DEBUG    Scheduler    ................job[cron]:{'0,15,25,35,45,55 * * *': '0', '0,10,20,30,40,50 * * *': '1'} -- scheduler.py:_next_time:293
      2013-12-08 01:10:01,106 DEBUG    Scheduler    aussen.vorn.licht2 next time: 2013-12-08 01:15:00+01:00 -- scheduler.py:_next_time:306
      2013-12-08 01:10:58,384 ERROR    Connections  KNX: could not connect to 127.0.0.1:6720 (TCP): [Errno 111] Connection refused -- connection.py:connect:380
      2013-12-08 01:11:11,517 DEBUG    env_stat     Item env.system.load = 0.04 via Logic None None -- item.py:__update:363
      2013-12-08 01:11:11,966 DEBUG    Scheduler    env_stat next time: 2013-12-08 01:16:11+01:00 -- scheduler.py:_next_time:306
      2013-12-08 01:15:00,048 DEBUG    aussen.vorn.licht2 Item aussen.vorn.licht2 = False via Scheduler None None -- item.py:__update:363
      2013-12-08 01:15:00,554 DEBUG    Scheduler    ................job[cron]:{'0,15,25,35,45,55 * * *': '0', '0,10,20,30,40,50 * * *': '1'} -- scheduler.py:_next_time:293
      2013-12-08 01:15:00,742 DEBUG    Scheduler    aussen.vorn.licht2 next time: 2013-12-08 01:20:00+01:00 -- scheduler.py:_next_time:306
      Angehängte Dateien

      Kommentar


        #4
        Update im 1. Post

        init und update im widget.js

        Dadurch ist das Select-Menu sofort mit den aktuellen crontab Werten initialisiert

        Kommentar


          #5
          Hi Dirk,

          danke für die Änderung, ist in develop.

          Bis bald

          Marcus

          Kommentar


            #6
            Konfiguration in der VISU

            Hallo Zusammen,
            der Ansatz einen konfigurierbaren Scheduler zu bauen habe ich für mich als sehr ansprechend gefunden, zumal ich den Google-Kalender nicht benutzen möchte.
            Daher habe ich versucht nach dieser Anleitung eine Zeitschaltuhr in meiner Installation umzusetzen.
            Ich bin erst vor kurzem in diese Materie eingestiegen und das einfache Nachbauen mag mir einfach nicht gelingen. (Ist hier auch mein erster Beitrag)
            Wie ist denn die Seite in SmartVISU zu konfigurieren?
            ich habe eine Zeile wie folgt eingebaut:
            {{ basic.crontab('zeitschaltuhr','aussen.vorn.licht2. zeitschaltuhr','Testschalter') }}

            Was ist denn in SmartVISU noch zu tun, damit es wie im oberen Beispiel aussieht?

            Bei mir sieht es bislang so aus:
            Angehängte Dateien

            Kommentar


              #7
              Thema Persistenz:

              aus dem anderen Thread kommt die Frage, wie der Zustand der variablen crontab-Einträge über einen Neustart zu retten wäre. Was auf die Frage hinaus läuft, wie die Initialisierung abläuft, wenn ein Item mit cache = on gespeichert wird:
              (Antwort: let the source be with you... Ist hier ein dokumentiertes Verhalten gesichert?)

              Zitat von walldi Beitrag anzeigen
              also persistieren könnte man ja das [zeitschaltuhr] Sub-Item (String mit den crontabs für ein- und ausschalten)

              Code:
                  [[[stedo2]]]
                      name = Steckdose2
                      type = bool
                          visu_acl = rw
                          sv_widget = "Zeitschaltuhr: {{ basic.crontab('item.zeitschaltuhr', 'item.zeitschaltuhr') }}"
                          knx_dpt = 1
                          knx_send = 0/0/33
                          knx_init = 0/1/33
                          enforce_update = yes
                      [[[[zeitschaltuhr]]]]
                              name = Zeitschaltuhr
                              type = foo
                              visu_acl = rw
                              enforce_update = yes
                                              [B]cache = on[/B]
              Jetzt müsste man nur noch den crontab beim Start richtig initialisieren.
              (logic mit crontab=init starten und entsprechend abfangen / ist dann Zeitschaltuhr schon aus dem cache initialisiert? / kann man das ggf forcieren? ... so viele Fragen )

              Kommentar


                #8
                Zitat von cassiopeia Beitrag anzeigen
                ...
                Daher habe ich versucht nach dieser Anleitung eine Zeitschaltuhr in meiner Installation umzusetzen.
                ...
                Was ist denn in SmartVISU noch zu tun, damit es wie im oberen Beispiel aussieht?
                Bei mir sieht es bislang so aus: ...
                Hallo,
                sorry für die späte Antwort. Ich bin nur sporadisch hier unterwegs. Daher kommentiere ich meine Beiträge immer nur als "Vorschläge" oder "Proof of Konzept", weil ich keinen Support zusichern kann.

                Zu deinem Versuch:
                Aussehen tut das genau so wie erwartet. Was Du brauchst, damit das im Ansatz funktioniert, ist der o.g. Patch (oder das Update auf develope) und die Logik zeitschaltuhr aus dem ersten Post.
                Hast Du das alles kopiert? Funktionierts? Was Steht im Debug-Log, wenn du auf (set) klickst und wenn die crontab getriggert wird? Wie sieht deine items.conf aus?

                Gruß, Dirk

                Kommentar


                  #9
                  AW: Thema Persistenz:

                  Wie ich eben sehe, gibt es da schon Antworten zu - danke Marcus! :
                  Damit sollte sich arbeiten lassen.

                  Zitat von mknx Beitrag anzeigen
                  Hallo,

                  in develop und ab 1.0 kann man init noch +/- integer mitgeben. Per default werden 'Init'-Logiken nach 5 Sekunden ausgeführt.

                  init-1 zieht die Ausführung eine Sekunde vor.
                  init+2 verzögert sie um zwei Sekunden.

                  Davon abgesehen gibt es, schon länger, die Funktion changed_by().
                  Diese liefert 'init' zurück wenn das Item noch nicht geändert wurde. Oder cache wenn es aus dem Cache aktualisiert wurde.

                  Bis bald

                  Marcus

                  Kommentar

                  Lädt...
                  X