Python Scheduling Application

From OpenCircuits
Jump to navigation Jump to search

Introduction

Such an early draft not ready for reading!!

Note that this is an article started by Russ Hensel, see "http://www.opencircuits.com/index.php?title=Russ_hensel#About My Articles" About My Articles

The purpose of this program is to give an all python application for scheduling activities on all platforms: win, mac, linux, raspberry pi. I wrote it because I did not find a suitable program ( with good documentation ) after a not too exhaustive search. So here it is, let me know if useful.

Features

  • Schedules events either running code internal to itself ( and anything you can write in Python ) or external applications.
  • Events can be run at fixed times or any other schedule you would like, from one time to an infinite time.
  • Python 3.6.
  • Extensible.
  • All Python, cross platform.
  • Some examples code/configurations in the download.
  • Parameter file allows some customization without programming.
  • Intended for Python programmers, not python naive uses ( sorry ).
  • Can email if special circumstances encountered.
  • Sleep tolerant ( but becomes inactive ).
  • GUI tracks recent events.
  • Maintains log file.
  • GUI runs in one thread, events ( now one at a time ) in another thread.

Use

There are 2 steps to creating a scheduling activity.

  • Create a new type of activity by programming ups it actions. This may not be necessary if an appropriate bit of code has already be written.
  • Edit the parameter file ( parameters.py ) to activate and schedule your the activity.

Explaining an Example Setup

Reading the section on design as well may help understand this section.

Parameters

The general parameter setup is explained in Configuration Files For Python and another example of its uses is discussed in Smart Terminal Parameter Examples There are additional features of the parameter setup here:

  • The additional use of a global dict is different in this application.
  • Most of the parameters are set up almost as soon as the application starts, but a second set of parameters is run from the processing_helper ( if any ) to set up additional parameters. This setup is delayed so that it can reference objects that have not be created until near the end of the application initialization. It is in the method: init_from_helper( ).

A Dictionary

Each scheduling activity may have its own ( but sharable ) set of parameters for that activity. These are stored in a dictionary, which is in turn stored in a master dictionary of all activity parameters. It is set up in parameters.py and is called: AppGlobal.parameter_dicts. When an event related function is called it is passed the name of the dictionary ( a string ) in AppGlobal.parameter_dicts and it gets out the correct dictionary it needs as in:

 a_dict     = AppGlobal.parameter_dicts[ a_dict_name ]

then individual elements are fetched as in:

 my_count   = a_dict["failed_connect_count"]

To keep the creation of a dictionary in one controllable spot I typically do it in its own method


    #   ------------------------------------
    def create_parm_dict_greenhouse( self, ):
            dict_name                       = "greenhouse"
            a_dict                          = {}

            a_dict["db_host"]               = '192.168.0.189'   #
            a_dict["db_port"]               = 3306
            a_dict["db_db"]                 = 'pi_db'

            a_dict["db_user"]               = 'pi_user'
            a_dict["db_passwd"]             = 'db_passwrd here'

            a_dict["sql_select"]            = "SELECT ev_time, temp_1, humid_1 FROM ev_data           WHERE ( ev_time > %s ) order by temp_1 asc"
            a_dict["select_timedelat"]      = datetime.timedelta( days= 0, hours = 0, minutes = 30  )

            a_dict["alarm_min_temp"]        = 50        # farenheight
            a_dict["alarm_max_temp"]        = 75

            a_dict["failed_connect_count"]  = 0
            a_dict["max_connect_count"]     = 4           # at 4 trigges an email
            a_dict["min_repeat_email_time"] = datetime.timedelta( days= 1, hours = 0, minutes = 0  )
            a_dict["time_last_email"]       = None

            AppGlobal.parameter_dicts[dict_name] = a_dict

Install

Get code from github, put where you put your python code, run. .... a bit more info later

Design

Events are packaged up basically as 2 functions that run at some time. The first function carries out the action you wish to schedule. The second function is more introspective: it typically looks at the event that has just been run and adjust the time of the event for its next run.

This means if you have an event that sends an email at 12:00 every day for 5 days, then at any time in the system it will exists only one event with a time in the future when it should be run. After the next time it is run it will count down the number of times it has been run ( stopping at 0 ) and reschedule itself for the next run.

Some Big Ideas

The things that "happen" are events, they are set up in the parameter file in the method init_from_helper( ) using another method add_event_next_given_time() (more methods of this time may be added in the future if needed ). The components of an event are the following:

  • A name for the event, to help you track it.
  • A function that is run when the event is due.
  • A time to first run the event ( minute, hour, day )
  • A name ( string ) to be used to access supplementray data/parameters related to the event.
  • A time delta for the next occurence after the specified when the event will be run again.
  • A count for the number of times to run/rerun the event, -1 = "forever" .
  • A function that is run after the event is run that is intended to reschedule the event in some way.
  • Most of the design is similar to Python Smart Terminal Technical except for the plug in processing modules.

Lets Look At Code

I will need to add code for a better example, for now I will use the example I have built.

Does What

This code is intended to connect to a remoter computer, make sure its database is alive and email me if it is not. Several attempts in a row must fail before the email is sent, and while the event keeps running, further email is blocked for some period of time.

Does How

The GUI

The graphical user interface runs in a separate thread from the events ( on thread for the gui, one thread for all the events )

The purpose of the GUI is to:

  • Give notice of each event as it is run and typically notes any exceptional conditions. Since this could take an almost unlimited amount of memory old events may be truncated.
  • Allow the user to interact with the system. At a later time I will post a screenshot and describe the function of the different components.

Logging

Standard Python logging, see: Python Smart Terminal Technical

Parameters

Basically the same way as in the Smart Terminal, some more details will follow, see: Python Smart Terminal Technical