Advertisement
Grayerbeard

combined02, w1thermsensor, raspberry pi, temperature control

Mar 16th, 2018
617
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 60.12 KB | None | 0 0
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. #   Keywords:
  4. #   Raspberry Pi, w1thermsensor, temperature control and monitoring, multiple sensors in parallel, pulse width mo control
  5. #   high current SCR (40amp)
  6. #   ref web site www.smalle.uk
  7. #   for use with Python 3
  8.  
  9. #   March 15th 2018   working byt sensor acquiring needs debugging- will probably sort later in the month.
  10. #  As of today March 16th can be seen working on http://www.smalle.uk/temps
  11.  
  12. #   Copyright 2018  <djgtorrens@gmail.com>
  13. #  
  14. #   This program is free software; you can redistribute it and/or modify
  15. #   it under the terms of the GNU General Public License as published by
  16. #   the Free Software Foundation; either version 2 of the License, or
  17. #   (at your option) any later version.
  18. #
  19. #   This program is distributed in the hope that it will be useful,
  20. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22. #   GNU General Public License for more details.
  23. #  
  24. #   You should have received a copy of the GNU General Public License
  25. #   along with this program; if not, write to the Free Software
  26. #   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  27. #   MA 02110-1301, USA.
  28.  
  29. print("Running combined02.py")
  30.  
  31. #additional imports for local display and sauna
  32. import myzero01 as led
  33. import RPi.GPIO as GPIO
  34.  
  35. # socket is for smartplug control
  36. import socket
  37.  
  38. # all other imports for rest of program
  39. import time
  40. import subprocess
  41. import datetime
  42. import csv
  43. # For Python 3
  44. import configparser
  45. # For Python 2.x would be
  46. #import ConfigParser as configparser
  47. #but this prog no good on Python 2
  48. from ftplib import FTP
  49. from os import listdir
  50. from os import path
  51. from os import fsync
  52. import sys, getopt
  53. import webbrowser
  54. from shutil import copyfile
  55. #Use with
  56. #copyfile(src, dst)
  57.  
  58. # Import w1thermsensor
  59. from w1thermsensor import W1ThermSensor
  60.  
  61. #   data class "config"  is used to hold configuration information
  62. #   the values set in initializing are the default values
  63. #   If no configuration file is found these values are writen to a file "config.cfg"
  64. # put in same directory as the python file.
  65. # the line
  66. # "  config.prog_path = path.dirname(path.realpath(__file__)) + "/"  "
  67. # using "path" from "os" module.
  68. # is used to get where to look for and put this file.
  69.  
  70. class class_config:
  71.     def __init__(self):
  72.         self.scan_delay = 1     # delay in seconds between each scan (not incl sensor responce times)
  73.         self.max_scans = 3          # number of scans to do, set to zero to scan for ever (until type "ctrl C")
  74.         self.log_directory = "/log/"        # where to send log files
  75.         self.ftp_credentials_filename = 'ftp_credentials.csv'   #
  76.         self.ftp_credentials_log_filename = 'ftp_credentials_log.csv'
  77.         self.ftp_credentials_status_filename = 'ftp_credentials_status.csv'
  78.         self.ftp_credentials_log_html_filename = 'ftp_credentials_log_html.csv'
  79.         self.mount_point = "/rtr/"      # the location to mount the share (must exist) e.g. /home/pi/rtr
  80.         self.test_file = "test.txt"         # a file that should be present at the share if its already mounted e.g.  test.txt
  81.         self.mount_arg1 = "sudo"        # first part of mount command (usually sudo)
  82.         self.mount_arg2 = "/etc/mount_log.sh"       # second part of mount command (usualy name of script to run)
  83.         self.delay_limit = 2        # Number of Seconds delay between temperature scans
  84.         self.delay_increment = 2        # Number of scans to do, Zero for only stopped by Ctrl C on Keyboard
  85.         self.ftplog = 2     # Number of Value Changes before Log File is Saved to remote website
  86.         self.heaterIPa = '192.168.111.100'      # IP for First Heater
  87.         self.heaterIPb = '192.168.111.108'      # IP for Second Heater
  88.         self.sensor4readings = '28-0315a80584ff'  #The code for the sensor to be used to measure room temperature
  89.         self.change4log = 0.6 # change in temperature required before logging and displaying etc
  90.         self.control_hysteresis = 1
  91.         self.default_target = 70 # Initial Default temperature target e.g for Sauna
  92.         self.precision = 12 # default precision is 12 bit
  93.         # These parameters are not saved to the config.cfg file
  94.         # First three use the program pathname
  95.         self.prog_path = ""
  96.         self.config_filename = ""
  97.         self.sensor_info_filename = ""
  98.         self.logging_filename_save_as = ""
  99.         self.logging_filename = ""
  100.         self.html_filename = ""
  101.         self.status_filename = ""
  102.         self.log_html_filename = ""
  103.         self.local_www_html_filename = ""
  104.         self.local_www_log_html_filename = ""
  105.         self.local_www_status_htlm_filename = ""
  106.         self.local_www_log_csv = ""
  107.         self.logging_on = False
  108.         self.sensor_present = False
  109.         self.logging_outfile = ""
  110.         self.scan_count = 0
  111.         self.ftplog_count = 0
  112.         self.ref_sensor_index = 0
  113.         self.heater1_on = 0
  114.         self.heater2_on = 0
  115.         self.one_first = 1
  116.         self.last_target = 0
  117.         self.number_seen = 0
  118.  
  119.                                 #  SENSORS
  120. class class_my_sensors:
  121.     def __init__(self):
  122.         self.number = []        # number designation of sensor to use for display
  123.         self.code = []          # the code that the sensor is internally programmed with
  124.         self.connected = []     # true/false flag indicating if his sensor is connected obtained by scanning for its file
  125.         self.reading = []       # the last temperature reading read from the sensor in degrees Centigrade,
  126.                                 # wil be a negative value < -100 if there is an error in reading
  127.         self.last_logged = []   # the value last logged for that sensor
  128.         self.code_seen = []     # a trie/false flag indicating that this senso code has been seen during this run
  129.         self.code_seen_but_disconnected = []    # Flag for when we have seen a sensor then its disconnected
  130.         self.location = []      # text read in from the sensor data file for the sensors location
  131.         self.stype = []         # text read in from the sensor data file for the sensors type
  132.         self.comment = []       # text read in from the sensor data file for a comment
  133.         self.delay = []         # if the sesor is not responding, maybe has become disconnected
  134.         self.error_number = []  # then its file will still be present for a while and this number is
  135.         self.last_logged_error_number = [] # Last logged error
  136.         self.status_text = []   # used to count down before retrying, initially set to the observed delay
  137.                                 # then 0.5 subtracted each scan until value less than 0.5.
  138.                                 # delay is usually around 2 secosnds so it will be about 3 scans before another attempt is made.
  139.  
  140.                    
  141. class class_schedule:
  142.     def __init__(self):
  143.         self.index = []     # Index of the array holding the Temperature Schedule
  144.         self.year = []      # Year
  145.         self.month = []     # Month
  146.         self.day = []       # Day
  147.         self.hour = []      # Hour
  148.         self.minute = []        # Minute
  149.         self.target_temp = []   # Target Temperature
  150.  
  151. class class_smartplug():
  152.     def __init__(self,number_of_plugs):
  153.                             # NOTE Set for 2 plugs,  
  154.                             # must introduce way to set number if need more
  155.         self.state  = [1.234]*number_of_plugs       # state on is "1" off "0"
  156.         self.ip = ["text"]*number_of_plugs          # ip address
  157.         self.current = [1.234]*number_of_plugs      # current
  158.         self.voltage = [1.234]*number_of_plugs      # voltage
  159.         self.power = [1.234]*number_of_plugs        # power now
  160.         self.total = [1.234]*number_of_plugs        # total power (today ?)
  161.         self.error = [1.234]*number_of_plugs        # error code
  162.         self.sent = ["command"]*number_of_plugs     # last command sent
  163.         self.received = ["reply"]*number_of_plugs   # last reply received
  164.  
  165. class textbffr(object):
  166.     # Rotating Buffer Class
  167.     # Initiate with just the size required Parameter
  168.     # Get data with just a position in buffer Parameter
  169.     def __init__(self, size_max):
  170.         #initialization
  171.         self.size_max = size_max
  172.         self._data = [""]*(size_max)
  173.         self.posn = self.size_max-1
  174.  
  175.     def replace(self, value):
  176.         #replace current element
  177.         self._data[self.posn] = value  
  178.  
  179.     def append(self, value):
  180.         #append an element
  181.         if self.posn == self.size_max-1:
  182.             self.posn = 0
  183.             self._data[self.posn] = value  
  184.         else:
  185.             self.posn += 1
  186.             self._data[self.posn] = value
  187.  
  188.     def __getitem__(self, key):
  189.         #return stored element
  190.         if (key + self.posn+1) > self.size_max-1:
  191.             return(self._data[key - (self.size_max-self.posn-1)])
  192.         else:
  193.             return(self._data[key + self.posn+1])
  194.  
  195. # **********************************
  196. # Start of small service functions *
  197. # **********************************
  198.  
  199. def in_GUI_mode():
  200.     mode = 1
  201.     try:
  202.         if sys.stdin.isatty():
  203.             mode = 0
  204.     except AttributeError:  # stdin is NoneType if not in terminal mode
  205.         pass
  206.     if mode == 0:
  207.         #in terminal mode
  208.         return(False)
  209.     else:
  210.         #in gui mode ...
  211.         return(True)
  212.  
  213. def list_files(path,exclude):
  214.     # List all files in path "path" bu exclude items matching "exclude"
  215.     # Result is returned as a list
  216.     here = "list_files"
  217.     emptylist= []
  218.     files = []
  219.     try:
  220.         seen_files = listdir(path)
  221.         pr(here,"Number of file found : ", str(len(seen_files)))
  222.         for ind in range(0,len(seen_files)):
  223.             if (seen_files[ind] == exclude) or (seen_files[ind][:2] == "00"):
  224.                 pr(here,"seen_file[" + str(ind)+"] is not OK : ",seen_files[ind])
  225.             else:  
  226.                 pr(here,"seen_file[" + str(ind)+"] is OK : ",seen_files[ind])
  227.                 files.append(seen_files[ind])
  228.         return(files)
  229.     except:
  230.         pr_status(True,0,"Error in subroutine list_files")
  231.         return(emptylist)  
  232.  
  233. def pt(where, message):
  234.     global debug
  235.     # routine for use debugging time taken each stage of program
  236.     if debug:
  237.         print("debug(pt) in: " , where , " : ", message, " at : " , str(datetime.datetime.now()), "\n")
  238.     return
  239.  
  240. def pr(where,message,var_val):
  241.     global debug
  242.     # routine for debugging that prints message then a variables value
  243.     if debug:
  244.         print("debug(pr) in : ", where , " : ", message, str(var_val))
  245.     return
  246.        
  247. def pr_f(where,message,var_val):
  248.     global debug_ftp
  249.     # routine for debugging ftp that prints message then a variables value
  250.     if debug_ftp:
  251.         print("debug_ftp(pr) in : ", where , " : ", message, str(var_val))     
  252.        
  253. def pr_w1(where,message,var_val):
  254.     global debug_w1
  255.     # routine for debugging when want to check operation of w1thermsensor only
  256.     if debug_w1:
  257.         print("debugW1 in : ", where , " : ", message, str(var_val))
  258.     return     
  259.        
  260.        
  261. def pr_status(appnd,ref,message):
  262.     global status_bffr
  263.     global last_ref
  264.     here = "pr_status"
  265.     # print to screen and to status log and update html file
  266.     print(str(config.scan_count), " : ", message)
  267.     if appnd:
  268.         status_bffr.append(str(config.scan_count) + " : " + make_time_text(datetime.datetime.now()) + " : " + message)
  269.     else :
  270.         if ref == last_ref:
  271.             status_bffr.replace(str(config.scan_count) + " : " + make_time_text(datetime.datetime.now()) + " : " + message)
  272.         else:
  273.             status_bffr.append(str(config.scan_count) + " : " + make_time_text(datetime.datetime.now()) + " : " + message)
  274.     write_html(config.status_filename,status_bffr)
  275.     try:
  276.         copyfile(config.status_filename, config.local_www_status_htlm_filename)
  277.     except:
  278.         pr_log (True,"Fail with send html file to " + config.local_www_status_htlm_filename)
  279.     pr_f(here, "FTP for Status file File names  : ", config.ftp_credentials_status_filename + " : " +  config.status_filename + " : " + "use_cred")
  280.     ftp_result = send_by_ftp(config.ftp_credentials_status_filename, config.status_filename, "use_cred")   
  281.     # next lines in effect when "f" option selected
  282.     for pres_ind in range(0, len(ftp_result)):
  283.         pr_f(here, str(pres_ind) + " : ", ftp_result[pres_ind])
  284.     last_ref = ref
  285.     return
  286.  
  287. def pr_log(appnd,message):
  288.     global log_bffr
  289.     here = "pr_log"
  290.     # print to screen and to status log and update html file
  291.     print(str(config.scan_count) + " : ",message)
  292.     if appnd :
  293.         log_bffr.append(str(config.scan_count) + " : " + message)
  294.     else:
  295.         log_bffr.replace(str(config.scan_count) + " : " + message)
  296.     write_html(config.log_html_filename,log_bffr)
  297.     try:
  298.         copyfile(config.log_html_filename, config.local_www_log_html_filename)
  299.     except:
  300.         pr_status(True,0, "Fail with send html file to " + config.local_www_log_html_filename)
  301.     pr_f(here, "FTP for log html file File names   : ", config.ftp_credentials_log_html_filename + " : " +  config.log_html_filename + " : " + "use_cred")
  302.     ftp_result = send_by_ftp(config.ftp_credentials_log_html_filename, config.log_html_filename, "use_cred")   
  303.     # next lines in effect when "f" option selected
  304.     for pres_ind in range(0,len(ftp_result)):
  305.         pr_f(here, str(pres_ind) + " : ",ftp_result[pres_ind])
  306.     return
  307.  
  308.  
  309. def fileexists(filename):
  310.     #This checks for file but does not detect disconnected sensor
  311.     try:
  312.             with open(filename): pass
  313.     except IOError:
  314.             return False
  315.     return True
  316.  
  317. def mount_log_drive(mount_point,test_file,mount_arg1,mount_arg2):
  318.    
  319.     # NOT IN USE AT THE MOMENT IN thermoxx.py
  320.    
  321.     #  mount_point  :   the location to mount the share (must exist) e.g. /rtr
  322.     #  test_file    :   a file that should be present at the share if its already mounted e.g.  test.txt
  323.     #  mount_arg1   :   first part of mount command (usually sudo)
  324.     #  mount_arg2   :   second part of mount command (usualy name of script to run such as 'sudo /etc/mount_log.sh')
  325.     #       typical script command "sudo mount -t cifs //192.168.1.1./log /home/pi/rtr -o credentials=/etc/mountcred,sec=ntlm
  326.     #       credentials_file:  a file containing the username and password (located in \etc) for the share e.g.  mountcred
  327.     #               typical credentials file:
  328.     #                   username=fredblogs
  329.     #                   password=reallysecurepassword
  330.  
  331.     #check to see if the network drive for logging is mounted, if not then mount it
  332.     here = "mount_log_drive"
  333.     if (fileexists(mount_point + test_file)):
  334.             pr_status(True,0, "Log Drive already mounted because " + mount_point + test_file + " exists")
  335.             return ("Log Drive already mounted\n")
  336.     else:
  337.             pr_status(True,0, "Will use mount command: " + mount_arg1 +  " " + mount_arg2 + "\n")
  338.             subprocess.call([mount_arg1,mount_arg2]) # e.g. applies 'sudo /etc/mount_log.sh' as two parts of the command
  339.             return("Log Drive now mounted\n")
  340.  
  341. def show_html(html_filename):
  342.     # open a file in the default program
  343.     here = "show_html"
  344.     pr(here, "Show file at this url : ", " file://" + html_filename)
  345.     url = "file://" + html_filename
  346.     webbrowser.open(url,new=2) # new=2 signals new tab
  347.  
  348. def print_bffr(bffr):
  349.     #print to screen contaents of a buffer
  350.     for ind in range(bffr.size_max-1,-1,-1):
  351.         stored = bffr[ind]
  352.         if stored != "":
  353.             print(stored)
  354.     print( '\n' )
  355.    
  356. def write_html(html_filename,bffr):
  357.     #send contemts of buffer to website
  358.     with open(html_filename,'w') as htmlfile:
  359.         htmlfile.write("<p>" + html_filename + " : " + make_time_text(datetime.datetime.now())  + "</p>")
  360.         for ind in range(bffr.size_max-1, -1,-1):
  361.             htmlfile.write("<p>" + bffr[ind] + "</p>")
  362.    
  363. def make_time_text(time_value):
  364.     #make a time stamp in format mm:dd hr:mn:sc
  365.     return(str(time_value.month).zfill(2) + "_" + str(time_value.day).zfill(2) + "__"
  366.       + str(time_value.hour).zfill(2) + "_" + str(time_value.minute).zfill(2) +"_"
  367.       + str(time_value.second).zfill(2))
  368.  
  369. # ***********************************
  370. #  End  of small service functions *
  371. # **********************************
  372.  
  373. # **********************************
  374. #  Start of local display functions *
  375. # **********************************
  376.  
  377.  
  378. def date(seconds):
  379.    
  380.     device = led.sevensegment()
  381.     deviceId = 0
  382.    
  383.     device.clear()
  384.    
  385.     for count in range(seconds):
  386.         now = datetime.datetime.now()
  387.         day = now.day
  388.         month = now.month
  389.         year = now.year - 2000
  390.  
  391.         # Set day
  392.         device.letter(deviceId, 8, int(day / 10))     # Tens
  393.         device.letter(deviceId, 7, day % 10)          # Ones
  394.         device.letter(deviceId, 6, '-')               # dash
  395.         # Set day
  396.         device.letter(deviceId, 5, int(month / 10))     # Tens
  397.         device.letter(deviceId, 4, month % 10)     # Ones
  398.         device.letter(deviceId, 3, '-')               # dash
  399.         # Set day
  400.         device.letter(deviceId, 2, int(year / 10))     # Tens
  401.         device.letter(deviceId, 1, year % 10)     # Ones
  402.         time.sleep(1)
  403.     device.clear()
  404.  
  405. def clock(seconds):
  406.    
  407.     device = led.sevensegment()
  408.     deviceId = 0
  409.    
  410.     device.clear() 
  411.    
  412.     for count in range(seconds):
  413.         now = datetime.datetime.now()
  414.         hour = now.hour
  415.         minute = now.minute
  416.         second = now.second
  417.         dot = second % 2 == 0               # calculate blinking dot
  418.         # Set hours
  419.         device.letter(deviceId, 4, int(hour / 10))   # Tens
  420.         device.letter(deviceId, 3, hour % 10, dot)   # Ones
  421.         # Set minutes
  422.         device.letter(deviceId, 2, int(minute / 10))   # Tens
  423.         device.letter(deviceId, 1, minute % 10)     # Ones
  424.         time.sleep(1)
  425.     device.clear()    
  426.  
  427. def show_numbers(left_number,right_number):
  428.  
  429.     device = led.sevensegment()
  430.     deviceId = 0
  431.    
  432.     device.clear()
  433.    
  434.     leftstr = str(left_number).zfill(3)
  435.     rightstr =str(right_number).zfill(3)
  436.    
  437.     print("will try to display", leftstr, rightstr)
  438.    
  439.     #device.letter(deviceId, 8, int(leftstr[0]))
  440.     device.letter(deviceId, 7, int(leftstr[0]))
  441.     device.letter(deviceId, 6, int(leftstr[1]) )
  442.     #device.letter(deviceId, 5, int(leftstr[3]))
  443.     #device.letter(deviceId, 4, int(leftstr[1]))
  444.     device.letter(deviceId, 3, int(rightstr[0]))
  445.     device.letter(deviceId, 2, int(rightstr[1]))
  446.     #device.letter(deviceId, 1, int(rightstr[3]))
  447.    
  448.    
  449.    
  450.    
  451.    
  452.    
  453. # **********************************
  454. #  End of local display functions *
  455. # **********************************
  456.  
  457. # ************************************
  458. #  Start smartplug service functions *
  459. # ************************************
  460.  
  461. # Check if IP is valid
  462. def validIP(ip):
  463.     try:
  464.         socket.inet_pton(socket.AF_INET, ip)
  465.     except socket.error:
  466.         parser.error("Invalid IP Address.")
  467.     return ip
  468.  
  469. # Predefined Smart Plug Commands
  470. # For a full list of commands, consult tplink_commands.txt
  471. commands = {'info'     : '{"system":{"get_sysinfo":{}}}',
  472.             'on'       : '{"system":{"set_relay_state":{"state":1}}}',
  473.             'off'      : '{"system":{"set_relay_state":{"state":0}}}',
  474.             'read'     : '{"emeter":{"get_realtime":{}}}'
  475. }
  476.  
  477. # Encryption and Decryption of TP-Link Smart Home Protocol
  478. # XOR Autokey Cipher with starting key = 171
  479. #revied code refer https://github.com/softScheck/tplink-smartplug/issues/20
  480. def encrypt(string):
  481.     key = 171
  482.     result = b"\0\0\0"+ chr(len(string)).encode('latin-1')
  483.     for i in string.encode('latin-1'):
  484.         a = key ^ i
  485.         key = a
  486.         result += chr(a).encode('latin-1')
  487.     return result
  488.  
  489. def decrypt(string):
  490.     key = 171
  491.     result = ""
  492.     for i in string:
  493.         a = key ^ i
  494.         key = i
  495.         result += chr(a)
  496.     return result
  497.    
  498. def get_json(string,value):
  499.     try:
  500.         pos = string.find(":",string.find(value))
  501.         if pos == -1 :
  502.             return -1
  503.         else:  
  504.             end1 = string.find(",",pos)
  505.             end2 = string.find("}",pos)
  506.         try:
  507.             return float(string[pos+1:end1])
  508.         except:
  509.             try:
  510.                 return float(string[pos+1:end2])
  511.             except:
  512.                 return -1
  513.     except: return -99
  514.  
  515. def  send_command(cmded,ip,port) :
  516.     try:
  517.         sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  518.         sock_tcp.connect((ip, port))
  519.         sock_tcp.send(encrypt(cmded))
  520.         data = sock_tcp.recv(2048)
  521.         sock_tcp.close()
  522.         return decrypt(data[4:])
  523.     except:
  524.         return ("error")
  525.        
  526. def get_smartplug_status():
  527.     global smartplug_info
  528.  
  529.     #temporary until imlement file to hold smartplug info separatly
  530.     smartplug_info.ip[0] = config.heaterIPa
  531.     smartplug_info.ip[1] = config.heaterIPb
  532.     #smartplug_info.ip[2] = "192.168.222.63"
  533.     #smartplug_info.ip[3] = "192.168.222.64"
  534.  
  535.     for index in range(0,len(smartplug_info.ip),1):
  536.         cmd = commands["read"]
  537.         result = send_command(cmd,smartplug_info.ip[index],9999)
  538.         if result != "error" :
  539.             st_cmd = commands["info"]
  540.             smartplug_info.state[index] = get_json(send_command(st_cmd,smartplug_info.ip[index],9999),"relay_state")
  541.             smartplug_info.current[index] = get_json(result,"current")
  542.             smartplug_info.voltage[index] = get_json(result,"voltage")
  543.             smartplug_info.power[index] = get_json(result,"power")
  544.             smartplug_info.total[index] = get_json(result,"total")
  545.             smartplug_info.error[index] = get_json(result,"err_code")
  546.             smartplug_info.sent[index] = cmd
  547.             smartplug_info.received[index] = result
  548.         else:
  549.             pr_status(True,0, "Error connecting to Smartplug on : " + smartplug_info.ip[index])
  550.  
  551. def turn_on_smartplug(index):
  552.     global config
  553.     cmd = commands["on"]
  554.     send_command(cmd,smartplug_info.ip[index],9999)        
  555.  
  556. def turn_off_smartplug(index):
  557.     global config
  558.     cmd = commands["off"]
  559.     send_command(cmd,smartplug_info.ip[index],9999)
  560.  
  561. # ************************************
  562. # End of smartplug service functions *
  563. # ************************************
  564.  
  565. def init(margs):
  566.     global config
  567.     global my_sensors
  568.     global temps_dir
  569.     global exclude_filename
  570.     global debug
  571.     global debug_w1
  572.     global debug_ftp
  573.     global error
  574.     global run_mode
  575.     global smartplug_info
  576.     global status_bffr
  577.     global log_bffr
  578.     global sauna
  579.     global sevenseg
  580.    
  581.     here = "init"
  582.    
  583.     #*****************************************************
  584.     # (1) set up buffers and sesnor data
  585.     #     and initialise various
  586.     #
  587.     log_bffr = textbffr(100)
  588.     status_bffr = textbffr(200)
  589.     my_sensors = class_my_sensors()
  590.    
  591.     init_printout = []
  592.  
  593.     debug = False
  594.     debug_w1 = False
  595.     debug_ftp = False
  596.     exit_flag = False
  597.     new_config_wanted = False
  598.     new_sensor_file_wanted = False
  599.     sauna = False # local Display
  600.     sevenseg = False
  601.    
  602.     config = class_config() # set all to defaults
  603.     config.last_target = 0
  604.    
  605.     starttime = datetime.datetime.now()
  606.     timestamp = make_time_text(starttime)
  607.     pr_f(here,"This is the time stamp used for log file >>>", timestamp + "<<<<")
  608.    
  609.     # GPIO pin set up for Sauna Control
  610.     GPIO.setmode(GPIO.BCM)
  611.     GPIO.setup(18, GPIO.OUT)
  612.    
  613.     #*****************************************************
  614.     # (2) Get the option Flags
  615.     #
  616.     options_ok = False
  617.     #try:
  618.     try:
  619.         opts, args = getopt.getopt(margs,"dhfsclmw")
  620.         options_ok = True
  621.         init_printout.append("No Options Errors")
  622.         for opt, arg in opts:
  623.             if opt == '-w':
  624.                 #debug the W1 function with extra printouts
  625.                 debug_w1 = True
  626.             if opt == '-m':
  627.                 #Sauna control without 7 Seg display
  628.                 init_printout.append("Option : " + opt)
  629.                 sauna = True
  630.                 sevenseg = False
  631.             if opt == '-l':
  632.                 #local control of sauna heater using SCR relay
  633.                 init_printout.append("Option : " + opt)
  634.                 sauna = True # script to run in Sauna Local { hence the l for local } Display.
  635.                 sevenseg = True
  636.             if opt == '-c':
  637.                 # cretae a new Config file and exit
  638.                 init_printout.append("Option : " + opt)
  639.                 new_config_wanted = True
  640.                 exit_flag = True
  641.             if opt == '-d':
  642.                 # extensive debug printouts
  643.                 init_printout.append("Option : " + opt)
  644.                 debug = True
  645.             if opt == '-h':
  646.                 # print help info on options
  647.                 init_printout.append("Option : " + opt)
  648.                 init_printout.append("Help on Options:")
  649.                 init_printout.append("Help             -h")
  650.                 init_printout.append("Make Sensor file -s")
  651.                 init_printout.append("Make Config file -c")
  652.                 init_printout.append("Debug            -d")
  653.                 init_printout.append("Debug ftp and file name creation -f")
  654.                 init_printout.append("Extra Printouts for W1 thermsensor use -w")
  655.                 init_printout.append("Local Control of SCR Relay -l")
  656.                 init_printout.append("Make Config file -c")
  657.                 # init_printout.append(" xxx -?")
  658.                 exit_flag = True
  659.             if opt == '-f':
  660.                 init_printout.append("Option : " + opt)
  661.                 debug_ftp = True
  662.             if opt == '-s':
  663.                 init_printout.append("Option : " + opt)
  664.                 exit_flag = True
  665.                 new_sensor_file_wanted = True
  666.    
  667.     except:
  668.         init_printout.append("Options error")              
  669.         init_printout.append("Correct Options are: ")
  670.         init_printout.append("Debug            -d")
  671.         init_printout.append("Help             -h")
  672.         init_printout.append("Debug ftp        -f")
  673.         init_printout.append("Make Sensor file -s")
  674.         init_printout.append("Make Config file -c")        
  675.         exit_flag = True
  676.                    
  677.    
  678.     #*****************************************************
  679.     # (3) determine the programs location and set up filenames
  680.     #  
  681.     config.prog_path = path.dirname(path.realpath(__file__))
  682.     pr_f(here,"config.prog_path : ", config.prog_path )
  683.     config.config_filename = config.prog_path + "/" + "config.cfg"
  684.     pr_f(here,"config.config_filename : ", config.config_filename) # OK
  685.     config.sensor_info_filename = config.prog_path + "/" + "sensor_data.csv"
  686.     pr_f(here,"config.sensor_info_filename: ", config.sensor_info_filename )
  687.     config.logging_filename_save_as = timestamp + "lg.csv"
  688.     pr_f(here,"config.logging_filename_save_as: ", config.logging_filename_save_as )
  689.     config.logging_filename =  config.prog_path + config.log_directory + config.logging_filename_save_as
  690.     pr_f(here,"config.logging_filename: ",  config.logging_filename )
  691.     config.html_filename = config.prog_path + "/" + "index.html"
  692.     pr_f(here,"config.html_filename: ",  config.html_filename)
  693.     config.status_filename = config.prog_path + "/" +"status.html"
  694.     pr_f(here,"config.status_filename: ",  config.status_filename )
  695.     config.log_html_filename = config.prog_path + "/" + "log.html"
  696.     pr_f(here,"config.log_html_filename : ",   config.log_html_filename)
  697.     config.local_www = "/var/www/html"
  698.     pr_f(here,"config.local_www: ",  config.local_www )
  699.    
  700.     config.local_www_html_filename = config.local_www + "/" +"index.html"
  701.     pr_f(here,"config.local_www_html_filename: ",config.local_www_html_filename )
  702.    
  703.     config.local_www_log_html_filename = config.local_www + "/" + "log.html"
  704.     pr_f(here,"config.local_www_log_html_filename : ", config.local_www_log_html_filename)
  705.    
  706.     config.local_www_status_htlm_filename = config.local_www + "/" + "status.html"
  707.     pr_f(here,"config.local_www_status_htlm_filename: ",  config.local_www_status_htlm_filename )
  708.    
  709.     config.local_www_log_csv = config.local_www + "/" + config.logging_filename_save_as
  710.     pr_f(here,"config.local_www_log_csv: ",  config.local_www_log_csv)
  711.  
  712.     #*****************************************************
  713.     # (3) Load in Configuration from config.cfg
  714.     #   (If no file then save defaults to config.cfg file)
  715.  
  716.     init_printout.append( "Will look for this config file : " + config.config_filename)
  717.     #set up configuration
  718.     if fileexists(config.config_filename) and new_config_wanted:
  719.         init_printout.append("For a default config file please first rename or delete old file")
  720.         exit_flag = True
  721.     elif new_config_wanted:
  722.         init_printout.append("New Config File Made with default values, now you can edit it")
  723.         config_write(config.config_filename,config)
  724.         exit_flag = True
  725.     else:
  726.         if fileexists(config.config_filename):     
  727.             init_printout.append("Config taken from file")
  728.             print( "will try to read Config File : " , config.config_filename )
  729.             config_read(config.config_filename) # overwrites from file
  730.         else : # no file so needs to be written
  731.             config_write(config.config_filename,config)
  732.             init_printout.append("New Config File Made with default values, you probably need to edit it")
  733.     #check for an existing sensor data file
  734.     if fileexists(config.sensor_info_filename) and new_sensor_file_wanted:
  735.         init_printout.append("For a new sensor data file please first rename or delete old file")
  736.         exit_flag = True
  737.     elif new_sensor_file_wanted:
  738.         codes_count = check_number_connected()
  739.         # then if there are any write to the new file
  740.         if codes_count >0 :
  741.             init_printout.append("Sensor Data found filecreated and can now be edited. It has "+ str(new_codes_count) + " entries" )
  742.             write_sensor_data(new_codes_count,True)
  743.         else:
  744.             init_printout.append("No sensors connected Please connect at least one")
  745.             exit_flag = True
  746.     elif fileexists(config.sensor_info_filename):
  747.         init_printout.append("Existing Sensor data file found and data read in")
  748.         # if there is a file with sensor data read it in
  749.         read_in_sensor_data(config.sensor_info_filename)
  750.         new_codes_count = get_temps()
  751.         #then if there are any new we have not seen before write to the sensor file
  752.         if new_codes_count >0 :
  753.             init_printout.append("New Sensors found"+ str(new_codes_count) + " new" )
  754.             write_sensor_data(new_codes_count,True)
  755.  
  756.     # Initial setup Complete so write messages
  757.     for initial_ind in range(0,len(init_printout)):
  758.         pr_status(True,"Initial : ",init_printout[initial_ind])
  759.        
  760.     if exit_flag:
  761.         sys.exit()
  762.  
  763.     #*****************************************************
  764.     # (5) mount remote drive using parameters from config.cfg
  765.     #       (mount_point,test_file,mount_arg1,mount_arg2)
  766.    
  767.     # NOT USED AT THE MOMENT IN thermoxx.py
  768.     #print(mount_log_drive(config.mount_point,config.test_file,config.mount_arg1,config.mount_arg2),"\n")
  769.  
  770.     #*****************************************************
  771.     # (6) set up log file using parameters from config.cfg
  772.     #       (file based is based on current time)
  773.  
  774.     if len(config.log_directory) > 0:
  775.         config.logging_outfile = open(config.logging_filename,'w')
  776.         config.logging_on = True
  777.     else:
  778.         config.logging_on = False
  779.         config.logging_filename = None
  780.         config.logging_outfile = ""
  781.  
  782.     #*****************************************************
  783.     # (7) Make sure the Gpio and thermometer modules are loaded
  784.     #       ()
  785.    
  786.     #Commented out for test
  787.     #subprocess.call(['sudo','modprobe', 'w1-gpio'])
  788.     #subprocess.call(['sudo','modprobe', 'w1-therm'])
  789.    
  790.  
  791.     #*****************************************************
  792.     # (9) set up empty lists to hold smartplug info
  793.     #       (see "class_smartplug" for information)
  794.     #  NOTE: Class is set from here for 2 (two) plugs
  795.     smartplug_info = class_smartplug(2)
  796.    
  797.     #*****************************************************
  798.     # (10) set up error codes
  799.     #       ()
  800.  
  801.     error=["OK","1File only","2New no Data","3Timeout","4CRC er",
  802.         "5Read Err","6Retry Err","7Error","8No Data","9No Dev","10Disconn"]
  803.        
  804.  
  805. def write_sensor_data(new_data_count, new_file):
  806.     # add a new record to the sensor file
  807.     global my_sensors
  808.     global config
  809.     global smartplug_info
  810.    
  811.     here = "write_sensor_data"
  812.     pr(here, "write_sensor_data will write : ", new_data_count)
  813.     fields = ['number','code','location','stype','comment']
  814.     # 'at' mode adds to end of the file and opens file as text
  815.     if new_file:
  816.         mode = 'wt'
  817.     else:
  818.         mode = 'at'
  819.     try:
  820.         with open(config.sensor_info_filename, mode) as sensorcsv_file:
  821.             writer = csv.DictWriter(sensorcsv_file, fieldnames = fields)
  822.             if new_file: # this is a blank file
  823.                 writer.writeheader() # new file needs headings.
  824.             for line_count in  range(len(my_sensors.code)-new_data_count,len(my_sensors.code),1):
  825.                 # We need to write to the new line with "number,code,location,stype,comment"
  826.                 writer.writerow({
  827.                 'number': my_sensors.number[line_count],
  828.                 'code': my_sensors.code[line_count],
  829.                 'location': my_sensors.location[line_count],
  830.                 'stype': my_sensors.stype[line_count],
  831.                 'comment': my_sensors.comment[line_count]
  832.                 })
  833.     except:
  834.         pr_status(True,0,"Error accessing the existing sensor info file")
  835.         pr_status(True,0,"Close the file if you are editing it!")
  836.         sys.exit()
  837.     return 0
  838.  
  839.  
  840. def config_read(c_filename):
  841.     here = "config_read"
  842.     config_read = configparser.RawConfigParser()
  843.     config_read.read(c_filename)
  844.     config.scan_delay = float(config_read.getint('SetUp', 'scan_delay'))
  845.     config.max_scans = int(config_read.getint('SetUp', 'max_scans'))
  846.     config.log_directory = config_read.get('SetUp', 'log_directory')
  847.     config.ftp_credentials_filename = config_read.get('SetUp', 'ftp_credentials_filename')
  848.     config.ftp_credentials_log_filename = config_read.get('SetUp', 'ftp_credentials_log_filename')
  849.     config.ftp_credentials_status_filename = config_read.get('SetUp', 'ftp_credentials_status_filename')
  850.     config.ftp_credentials_log_html_filename= config_read.get('SetUp', 'ftp_credentials_log_html_filename')
  851.     config.mount_point = config_read.get('SetUp', 'mount_point')
  852.     config.test_file = config_read.get('SetUp', 'test_file')
  853.     config.mount_arg1 = config_read.get('SetUp', 'mount_arg1')
  854.     config.mount_arg2 = config_read.get('SetUp', 'mount_arg2')
  855.     config.delay_limit = float(config_read.get('SetUp', 'delay_limit'))
  856.     config.delay_increment = float(config_read.get('SetUp', 'delay_increment'))
  857.     config.ftplog = float(config_read.get('SetUp', 'ftplog'))
  858.     config.heaterIPa = config_read.get('SetUp', 'heaterIPa')
  859.     config.heaterIPb = config_read.get('SetUp', 'heaterIPb')
  860.     config.sensor4readings = config_read.get('SetUp', 'sensor4readings')
  861.     config.change4log = config_read.get('SetUp', 'change4log')
  862.     config.control_hysteresis = float(config_read.get('SetUp', 'control_hysteresis'))
  863.     config.default_target = float(config_read.get('SetUp', 'default_target'))
  864.     config.precision = int(config_read.get('SetUp', 'precision'))
  865.     return
  866.  
  867. def config_write(c_filename,default_config):
  868.     here = "config_write"
  869.     config_write = configparser.RawConfigParser()
  870.     config_write.add_section('SetUp')
  871.     config_write.set('SetUp', 'scan_delay',default_config.scan_delay)
  872.     config_write.set('SetUp', 'max_scans',default_config.max_scans)
  873.     config_write.set('SetUp', 'log_directory',default_config.log_directory)
  874.     config_write.set('SetUp', 'ftp_credentials_filename',default_config.ftp_credentials_filename)
  875.     config_write.set('SetUp', 'ftp_credentials_log_filename',default_config.ftp_credentials_log_filename)
  876.     config_write.set('SetUp', 'ftp_credentials_status_filename',default_config.ftp_credentials_status_filename)
  877.     config_write.set('SetUp', 'ftp_credentials_log_html_filename',default_config.ftp_credentials_log_html_filename)
  878.     config_write.set('SetUp', 'mount_point',default_config.mount_point)
  879.     config_write.set('SetUp', 'test_file',default_config.test_file)
  880.     config_write.set('SetUp', 'mount_arg1',default_config.mount_arg1)
  881.     config_write.set('SetUp', 'mount_arg2',default_config.mount_arg2)
  882.     config_write.set('SetUp', 'scan_delay',default_config.scan_delay)
  883.     config_write.set('SetUp', 'delay_limit',default_config.delay_limit)
  884.     config_write.set('SetUp', 'delay_increment',default_config.delay_increment)
  885.     config_write.set('SetUp', 'ftplog',default_config.ftplog)
  886.     config_write.set('SetUp', 'heaterIPa',default_config.heaterIPa)
  887.     config_write.set('SetUp', 'heaterIPb',default_config.heaterIPb)
  888.     config_write.set('SetUp', 'sensor4readings',default_config.sensor4readings)
  889.     config_write.set('SetUp', 'change4log',default_config.change4log)
  890.     config_write.set('SetUp', 'control_hysteresis',default_config.control_hysteresis)
  891.     config_write.set('SetUp', 'default_target',default_config.default_target)
  892.     config.write.set('SetUp', 'precision',default_config.precision)
  893. # Writing our configuration file to 'c_filename'
  894.     pr(here, "ready to writenew : " , c_filename)
  895.     with open(c_filename, 'w+') as configfile:
  896.         config_write.write(configfile)
  897.     return 0
  898.  
  899. def read_in_sensor_data(s_filename):
  900.     #   Set sensor data lists with initial values
  901.     #   read in from file if it exists if not then set up
  902.     #   just defaults for one sensor
  903.     #   later any sensors that are connected will be added
  904.     global my_sensors
  905.     global smartplug_info
  906.     global config
  907.     here = "read_in_sensor_data"
  908.     pr(here, "dictionary of my_sensors : ", my_sensors.__dict__ )
  909.     with open(s_filename, 'r') as csvfile:
  910.         d_file = csv.DictReader(csvfile)
  911.         ind = 0
  912.         for row in d_file:
  913.             my_sensors.number.append(row['number'])
  914.             my_sensors.code.append(row['code'])
  915.             my_sensors.connected.append(False)
  916.             my_sensors.reading.append(-108)
  917.             my_sensors.last_logged.append(-108)
  918.             my_sensors.code_seen.append(False)
  919.             my_sensors.code_seen_but_disconnected.append(False)
  920.             my_sensors.location.append(row['location'])
  921.             my_sensors.stype.append(row['stype'])
  922.             my_sensors.comment.append(row['comment'])
  923.             my_sensors.delay.append(0)
  924.             my_sensors.error_number.append(2)
  925.             my_sensors.last_logged_error_number.append(2)
  926.             my_sensors.status_text.append("?")
  927.         ind += 1
  928.     return(True)
  929.  
  930. def read_in_schedule_data(sch_filename):
  931.     #   Read in Schedule data from schedule.csv
  932.     global my_sensors
  933.     global smartplug_info
  934.     global config
  935.     here = "read_in_schedule_data"
  936.     pr(here, "Schedulke Data read in : ", schedule.__dict__ )
  937.     with open( config.prog_path + "/schedule.csv", 'r') as csvfile:
  938.         d_file = csv.DictReader(csvfile)
  939.         ind = 0
  940.         for row in d_file:
  941.             schedule.index.append(row['index'])
  942.             schedule.year.append(row['year'])
  943.             schedule.month.append(row['month'])
  944.             schedule.day.append(row['day'])
  945.             schedule.hour.append(row['hour'])
  946.             schedule.minute.append(row['minute'])
  947.             schedule.target_temp.append(row['target_temp'])
  948.         ind += 1
  949.     return(True)
  950.  
  951. def send_by_ftp(ftp_cred,send_filename, save_as_filename):
  952.     here = "send_by_ftp"
  953.     result = ["FTP attempt for :" + send_filename]
  954.     # if controlling Sauna do not need to send by FTP
  955.     if not sauna :
  956.         try:
  957.             with open(ftp_cred, 'r') as csvfile:
  958.                 cred_file = csv.DictReader(csvfile)
  959.                 ind = 0
  960.                 for row in cred_file:
  961.                     if ind == 0:
  962.                         ftp_user = row['user']
  963.                         pr_f(here ,"ftpuser : ",ftp_user)
  964.                         ftp_password = row['password']
  965.                         pr_f(here,"ftp password : ", ftp_password)
  966.                         file_2_send = str(send_filename)
  967.                         if save_as_filename == "use_cred":
  968.                         #use filename from credentials file
  969.                             file_as = str(row['file_as'])
  970.                         else:
  971.                         # use file from function parameter
  972.                             file_as = save_as_filename
  973.                         ftp_directory = str(row['directory'])
  974.                         pr_f(here, "ftp directory : ",ftp_directory)
  975.                         ftp_site =  str(row['site'])
  976.                         pr_f(here, "ftp site : ", ftp_site)
  977.                     else:
  978.                         result.append("Error more than one line in FTP Credentials file")
  979.                         return(result)
  980.                     ind += 1
  981.             ftp = FTP()
  982.             pr_f(here,"Will try to connect to : ", ftp_site)
  983.             ftp.connect(ftp_site, 21)
  984.             pr_f(here, "logging in here is ftp welcome message : ",ftp.getwelcome())
  985.             ftp.login(user=ftp_user,passwd=ftp_password)
  986.             pr_f(here, "logged in to : ",ftp_site)
  987.             ftp.cwd(ftp_directory)
  988.             pr_f(here, "directory changed to : ", ftp_directory)  
  989.        
  990.             sendfile  = open(send_filename,'rb')
  991.             result.append("Will try to send : " + send_filename + " : as : "
  992.                          + file_as + " to : " +  ftp_site + "/" + ftp_directory)
  993.             ftp.storbinary('STOR ' + file_as,sendfile)
  994.             sendfile.close()
  995.            
  996.             ftp.quit()
  997.             pr_f(here, "ftp quitedfrom : ", ftp_site)
  998.             pr_f(here,"Done FTP")
  999.             return(result)
  1000.         except:
  1001.             pr_f(here,"Failed FTP",save_as_filename)
  1002.             result.append("Error Trying To Send " + send_filename + " file by FTP")
  1003.     return(result)
  1004.    
  1005.  
  1006. def send_temperature_data_using_ftp(ftp_credentials_file):
  1007.     global config # set n init() used to hold FTP credentials
  1008.     global my_sensors # sensor data
  1009.     global smartplug_info
  1010.     global target_temp
  1011.  
  1012.     here = "send_temperature_data_using_ftp"
  1013.     ftp_text_top = ["\t<!--"]
  1014.     ftp_text_top.append("\Temperature Logging and Control")
  1015.     ftp_text_top.append("\t-->")
  1016.     ftp_text_top.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"")
  1017.     ftp_text_top.append("\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">")
  1018.     ftp_text_top.append("<htmlError Trying To Send xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">")
  1019.     ftp_text_top.append("<head>")
  1020.     ftp_text_top.append("\t<title>Temperature Logging and Control</title>")
  1021.     ftp_text_top.append("\t<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />")
  1022.     ftp_text_top.append("\t<meta name=\"generator\" content=\"Geany 1.27\" />")
  1023.     ftp_text_top.append("\t<meta http-equiv=\"refresh\" content=\"15\" />")
  1024.     ftp_text_top.append("</head>")
  1025.     # ftp_text_top.append("" + str(config.scan_count) + " System Time: "
  1026.     #                   + make_time_text(datetime.datetime.now()) + " Log File: "  + str(config.logging_filename))
  1027.     ftp_text_top.append("<body>")
  1028.     ftp_text_top.append("<table style=\"background-color: #f4e7e7; width: 350px; height: 150px; border: 1px  \
  1029.                           solid #1b58e4;\" cellpadding=\"5\" align=\"center\"><caption>Temperatures Logging</caption>")
  1030.     ftp_text_top.append("<tbody>")
  1031.     ftp_text_linestart = "<tr align=\"center\" valign=\"middle\"><td>"
  1032.     ftp_text_between = "</td><td>"
  1033.     ftp_text_line_end = "</td></tr>"
  1034.     ftp_text_end = ["</tbody>"]
  1035.     ftp_text_end.append("</table>")
  1036.     ftp_text_end.append("</body>")
  1037.     ftp_text_end.append("</html>")
  1038.     with open(config.html_filename,'w') as htmlfile:
  1039.         for element in ftp_text_top:
  1040.             htmlfile.write(element)
  1041.         htmlfile.write(ftp_text_linestart + " Scan Count:  " + ftp_text_between  \
  1042.                                           + str(config.scan_count) + ftp_text_line_end)
  1043.         htmlfile.write(ftp_text_linestart + "  System Time: " + ftp_text_between  \
  1044.                                           + make_time_text(datetime.datetime.now()) + ftp_text_line_end)
  1045.         htmlfile.write(ftp_text_linestart + " Html Log File: " + ftp_text_between \
  1046.                                           + "<a href=\"log.html\" target = \"_blank\">log.html</a>" + ftp_text_line_end)
  1047.         htmlfile.write(ftp_text_linestart + " Status File: " + ftp_text_between   \
  1048.                                           + "<a href=\"status.html\" target = \"_blank\">status.html</a>"  + ftp_text_line_end)
  1049.         htmlfile.write(ftp_text_linestart + " CSV Log File: " + ftp_text_between   \
  1050.                                           + "<a href=" + "\"" + str(config.logging_filename_save_as) + "\"" + "target = \"_blank\">" + str(config.logging_filename_save_as) + "</a>"  + ftp_text_line_end)
  1051.         s_numb = 0
  1052.         for element in my_sensors.number:
  1053.             htmlfile.write(ftp_text_linestart + str(element) + ftp_text_between + str(my_sensors.location[s_numb]) + ftp_text_between + str(my_sensors.status_text[s_numb]) + ftp_text_line_end)
  1054.             s_numb +=1
  1055.         if sauna:
  1056.             htmlfile.write(ftp_text_linestart + "Sauna" + ftp_text_between + "Target Temp : " + ftp_text_between + str(target_temp) + ftp_text_line_end)
  1057.         else:  
  1058.             htmlfile.write(ftp_text_linestart + "Plug 1 Power and Total" + ftp_text_between + str(smartplug_info.power[0]) + ftp_text_between + str(smartplug_info.total[0]) + ftp_text_line_end)
  1059.             htmlfile.write(ftp_text_linestart + "Plug 2 Power and Total"+ ftp_text_between + str(smartplug_info.power[1]) + ftp_text_between + str(smartplug_info.total[1]) + ftp_text_line_end)
  1060.             htmlfile.write(ftp_text_linestart + "Scehduled" + ftp_text_between + "Target Temp : " + ftp_text_between + str(target_temp) + ftp_text_line_end)
  1061.         for element in ftp_text_end:
  1062.             htmlfile.write(element)
  1063.    
  1064.     ftp_result = send_by_ftp(ftp_credentials_file, config.html_filename, "use_cred")
  1065.     for pres_ind in range(0,len(ftp_result)):
  1066.         pr_f(here, str(pres_ind) + " : ", ftp_result[pres_ind])
  1067.    
  1068.     try:
  1069.         # send the same html file to the local web site
  1070.         copyfile(config.html_filename, config.local_www_html_filename)
  1071.         # remove # on next line for debug
  1072.         # pr_status(True,0, "Sent : " + config.html_filename + " to : " + config.local_www_html_filename)
  1073.     except:
  1074.         pr_status(True,0,"Fail with copy " + config.html_filename + " to : " + config.local_www_html_filename)
  1075.    
  1076. def check_number_connected():
  1077.     sensors = W1ThermSensor.get_available_sensors()
  1078.     return(len(sensors))
  1079.  
  1080. def get_temps():
  1081.     # check which sensors are connected and update relavant flags
  1082.     # build a list of all the new sensors and then add them to the data in use
  1083.     # note :  requires that my_sensors variable is populated
  1084.     global my_sensors
  1085.     global dropped_list
  1086.     global smartplug_info
  1087.     global config
  1088.     here = "get_temps"
  1089.     # Look for what sensors are connected  
  1090.     sensors = W1ThermSensor.get_available_sensors()
  1091.     connected_codes = ["nocodeyet"]*len(sensors)
  1092.     connected_temp = [-100]*len(sensors)
  1093.    
  1094.     pr_w1 (here, " number seen", len(sensors) )
  1095.    
  1096.     ind = 0
  1097.    
  1098.     for individual_sensor in W1ThermSensor.get_available_sensors():
  1099.         #follwoing does not work so commented out
  1100.         #try:
  1101.             #individual_sensor.set_precision(config.precision)
  1102.         #except:
  1103.         #   pr_w1(here, "Cannot Change Precision" , str(individual_sensor.id) )
  1104.         connected_codes[ind] =  individual_sensor.id
  1105.         try:
  1106.             connected_temp[ind] = individual_sensor.get_temperature()
  1107.         except:
  1108.             pr_w1(here, "Error Reading scanned item", str(ind)  + " : " + individual_sensor.id)
  1109.             connected_temp[ind] = -100
  1110.         pr_w1(here   ,  "Scan of seen sensors" ,   str(ind) + " : " + connected_codes[ind] + " : " + str(connected_temp[ind]))
  1111.         ind += 1
  1112.    
  1113.     config.number_seen = ind
  1114.    
  1115.     if len(sensors) > 0:
  1116.         config.sensor_present = True
  1117.         pr_w1(here, "Sensor present Set True with count equal to : ", str(len(connected_codes)))
  1118.     else:
  1119.         pr_w1(here, "Sensor present not Set with count equal to : ", str(len(connected_codes)))
  1120.         config.sensor_present = False
  1121.    
  1122.     new_codes = []
  1123.     config.ref_sensor_index = -1
  1124.     dropped_list = ""
  1125.     for my_sensor_count in range(0,len(my_sensors.code)):
  1126.         my_sensors.code_seen[my_sensor_count] = False
  1127.         my_sensors.reading[my_sensor_count] = -100 # signal that no data seen
  1128.         my_sensors.error_number[my_sensor_count] += 1
  1129.         for seen_count in range (0,config.number_seen):
  1130.             if connected_codes[seen_count] == my_sensors.code[my_sensor_count]:
  1131.                 # set flag to indicate has been seen during this run of program
  1132.                 pr_w1 (here, "Scanning My Count, seen count ", str(my_sensor_count) + " :" + str(seen_count) + " : " +  str(connected_temp[seen_count]) )
  1133.                 my_sensors.code_seen[my_sensor_count] = True
  1134.                 my_sensors.connected[my_sensor_count] = True
  1135.                 my_sensors.error_number[my_sensor_count] = 0  # signal that its not in error
  1136.                 if connected_temp[seen_count] != -100:
  1137.                     # code there but not ready to be read
  1138.                     my_sensors.reading[my_sensor_count] = connected_temp[seen_count] # copy across id temp found
  1139.                 else:
  1140.                     my_sensors.reading[my_sensor_count] = -100
  1141.                     my_sensors.code_seen[my_sensor_count] = False
  1142.                     my_sensors.error_number[my_sensor_count] = 1
  1143.                 if my_sensors.code[my_sensor_count] == config.sensor4readings:
  1144.                     config.ref_sensor_index = my_sensor_count
  1145.                 my_sensors.code_seen_but_disconnected[my_sensor_count] = False
  1146.     count_connected = 0
  1147.     new_codes = []
  1148.     for element in connected_codes:
  1149.         if not element in my_sensors.code:
  1150.             new_codes.append(element)
  1151.         count_connected  += 1
  1152.     if len(new_codes) > 0:
  1153.         pr_w1(here, str(len(new_codes)), " new sensors found")
  1154.         pr_w1(here, " New sensors found ",len(new_codes))
  1155.         for ind in range(0, len(new_codes)):
  1156.             if len(my_sensors.number) > 0:
  1157.                 my_sensors.number.append("n" + str(count_connected-len(new_codes)+ind+1))
  1158.             else:
  1159.                 my_sensors.number.append("n" + str(1))
  1160.             my_sensors.code.append(new_codes[ind])
  1161.             my_sensors.connected.append(True)
  1162.             my_sensors.reading.append(-102)
  1163.             my_sensors.last_logged.append(-102)
  1164.             my_sensors.code_seen.append(True)
  1165.             my_sensors.code_seen_but_disconnected.append(False)
  1166.             my_sensors.location.append("New Sensor " + str(my_sensors.number[ind]) + " Location")
  1167.             my_sensors.stype.append("New Sensor " + str(my_sensors.number[ind]) + " Type")
  1168.             my_sensors.comment.append("New Sensor " + str(my_sensors.number[ind]) + " Comment")
  1169.             my_sensors.delay.append(0)
  1170.             my_sensors.error_number.append(2)
  1171.             my_sensors.status_text.append("New")
  1172.             my_sensors.last_logged_error_number.append(2)
  1173.     else:
  1174.         pr_w1(here, "no new codes, still only : ", str(count_connected) + " connected")
  1175.     return(len(new_codes))
  1176.  
  1177. def log_temperature_data_to_file():
  1178.     global config
  1179.     global sensors
  1180.     global smartplug_info
  1181.     global sauna_on
  1182.     global sauna_off
  1183.     global control_error
  1184.     here =  "log_temperature_data_to_file"
  1185.     #write the time at the start of the line in logging file
  1186.     logtime = datetime.datetime.now()
  1187.     config.logging_outfile.write(str(logtime.day).zfill(2) + "/" + str(logtime.month).zfill(2) +
  1188.         "/" + str(logtime.year).zfill(2) + " " + str(logtime.hour).zfill(2) + ":" +
  1189.         str(logtime.minute).zfill(2) + ":" + str(logtime.second).zfill(2))
  1190.     if (config.sensor_present == False):
  1191.         config.logging_outfile.write(" : no sensors with Trg Temp of : " + str(target_temp) + "\n")
  1192.     else:
  1193.         config.logging_outfile.write(",TrgTemp: ," + str(target_temp) + ",")
  1194.         for z in range(0,len(my_sensors.code),1):
  1195.             #record the data last saved for this sensor
  1196.             #send data to the file only if the sensor is connected
  1197.             if my_sensors.code_seen[z]:
  1198.                 config.logging_outfile.write(" , " + str(my_sensors.number[z]) + " , " + str(my_sensors.status_text[z]))
  1199.                 my_sensors.last_logged[z] = my_sensors.reading[z]
  1200.                 my_sensors.last_logged_error_number[z] = my_sensors.error_number[z]
  1201.        
  1202.         if sauna :
  1203.             config.logging_outfile.write(", Error/On/Off ." + str(control_error) + "," + str(sauna_on) + "," + str(sauna_off))
  1204.             config.logging_outfile.write("\n")
  1205.             config.logging_outfile.flush()
  1206.             return
  1207.         else:  
  1208.             get_smartplug_status()
  1209.             config.logging_outfile.write("," + str(smartplug_info.state[0]))
  1210.             config.logging_outfile.write("," + str(smartplug_info.current[0]))
  1211.             config.logging_outfile.write("," + str(smartplug_info.voltage[0]))
  1212.             config.logging_outfile.write(" , " + str(smartplug_info.power[0]))
  1213.             config.logging_outfile.write("," + str(smartplug_info.total[0]))
  1214.             config.logging_outfile.write("," + str(smartplug_info.error[0]))
  1215.             config.logging_outfile.write("," + str(smartplug_info.state[1]))
  1216.             config.logging_outfile.write("," + str(smartplug_info.current[1]))
  1217.             config.logging_outfile.write("," + str(smartplug_info.voltage[1]))
  1218.             config.logging_outfile.write("," + str(smartplug_info.power[1]))
  1219.             config.logging_outfile.write("," + str(smartplug_info.total[1]))
  1220.             config.logging_outfile.write("," + str(smartplug_info.error[1]))
  1221.             config.logging_outfile.write("\n")
  1222.             config.logging_outfile.flush()
  1223.  
  1224.     return
  1225.    
  1226. def set_status_text():
  1227.     # set the status text based on the results of the last scan
  1228.     error_count = 0
  1229.     here = "set_status_text"
  1230.     for z in range(0,len(my_sensors.code),1):
  1231.         pr_w1(here, "setting status text (index:error:reading) ", str(z) + " : " + str(my_sensors.error_number[z]) + " : " +  str(my_sensors.reading[z]))
  1232.         if my_sensors.error_number[z] == 0 :
  1233.             my_sensors.status_text[z] = ("{0:.4}".format(my_sensors.reading[z]))
  1234.         else:
  1235.             error_count +=1
  1236.             if my_sensors.delay[z] >= config.delay_limit:
  1237.                 my_sensors.status_text[z] = ("Wait" + str(int(my_sensors.delay[z])))
  1238.             else:
  1239.                 my_sensors.status_text[z] = ("ErrorCount" + str(my_sensors.error_number[z]))
  1240.    
  1241. def make_printout_for_screen(datachange):
  1242.     global config
  1243.     global my_sensors
  1244.     global smartplug_info
  1245.     global target_temp
  1246.     here = "make_printout_for_screen"
  1247.     error_count = 0
  1248.     #set printout for start of the line
  1249.     printout = str(config.scan_count) + " of " + str(config.max_scans) + " " + datetime.datetime.now().strftime("%d:%m:%Y %H:%M:%S") + " Target: " +  str(target_temp)
  1250.     for z in range(0,len(my_sensors.code),1):
  1251.         if my_sensors.connected[z]:
  1252.             printout += "[" + str(my_sensors.number[z]) + "=" + my_sensors.status_text[z] + "]"
  1253.         else:
  1254.             if my_sensors.code_seen[z]:
  1255.                 printout += "[" + str(my_sensors.number[z]) + "= disconn ]"
  1256.     printout += "  "
  1257.     #if not datachange:
  1258.     #   printout += "[no changes]"
  1259.     if max(my_sensors.delay) >= config.delay_limit:
  1260.         printout +="[max delay count:" + "{0:.4}".format(max(my_sensors.delay)) +"]"
  1261.     if len(dropped_list) > 0:
  1262.         printout += "[disconnected:" + dropped_list + "]"
  1263.     if error_count >0 :
  1264.         printout += "[error count=" + str(error_count) +"]"
  1265.     if not max(my_sensors.connected):
  1266.         printout += "[no sensors]"
  1267.     return(printout)
  1268.    
  1269. def get_target_temp(year,month,day,hour,minute):
  1270.     global schedule
  1271.     global config
  1272.        
  1273. # From Scedule get Target Temperature
  1274.             # Search for Target Temp
  1275.     target_temp = -100
  1276.     ind_result = 1
  1277.    
  1278.     for ind in range(1,len(schedule.year)):
  1279.         if int(year) == int(schedule.year[ind]):
  1280.             if int(month) == int(schedule.month[ind]):
  1281.                 if int(day) == int(schedule.day[ind]):
  1282.                     if int(hour) == int(schedule.hour[ind]):
  1283.                         if int(minute) >= int(schedule.minute[ind]):
  1284.                             if int(minute) <= int(schedule.minute[ind+1]):
  1285.                                 ind_result = ind
  1286.                                 break
  1287.                             else:
  1288.                                 ind_result = ind   
  1289.     if config.last_target != schedule.target_temp[ind_result+1]:
  1290.         pr_status(True,0, " config.last_target : " + str(config.last_target) + "   New Target : " +
  1291.                 str(schedule.target_temp[ind_result+1]))       
  1292.     config.last_target = schedule.target_temp[ind_result+1]
  1293.  
  1294.    
  1295.     if ind_result == 1:
  1296.         pr_status(True,0,"Error or very new schedule >> ind result : " + str(ind_result) + "Target set to 17.654321")
  1297.         return (17.654321)
  1298.     else:
  1299.         if ind_result +1 > len(schedule.year):
  1300.             pr_status(True,0,"Error>> ind result : " + ind_result +  "Target set to 16.54321")
  1301.             return (16.54321)
  1302.         else:
  1303.             # remove # in next 4 lines for debug
  1304.             #pr_status(True,0,"Schedule Look Up Result>> index used: " + str(ind_result+1).zfill(4) + "  Date : "
  1305.             # + str(schedule.year[ind_result+1]).zfill(4) + "/" + str(schedule.month[ind_result+1]).zfill(2) + "/"
  1306.             # + str(schedule.day[ind_result+1]).zfill(2) +" Time: " + str(schedule.hour[ind_result+1]).zfill(2) +":"
  1307.             # + str(schedule.minute[ind_result+1]).zfill(2) +" Target : " + str(schedule.target_temp[ind_result+1]))
  1308.             return (float(schedule.target_temp[ind_result+1]))
  1309.                
  1310.    
  1311. def main(argv):
  1312.     global config
  1313.     global starttime
  1314.     global my_sensors
  1315.     global schedule
  1316.     global debug
  1317.     global target_temp
  1318.     global status_bffr
  1319.     global log_bffr
  1320.     global last_ref
  1321.     global sauna
  1322.     global sauna_on
  1323.     global sauna_off
  1324.     global control_error
  1325.    
  1326.     last_ref = -1
  1327.     min_on = 0.75
  1328.     period = 12
  1329.     sauna_on = period
  1330.     sauna_off = 0
  1331.    
  1332.     here = "main"
  1333.     #Set things up and read in
  1334.     init(argv) # 6 tasks setting up variables etc
  1335.  
  1336.    
  1337.     # if there is a schedule file read it in
  1338.     pr_status(True,0,"Loading Schedule File Data from :  " + config.prog_path + "/schedule.csv")
  1339.     if fileexists(config.prog_path + "/schedule.csv"):
  1340.         schedule = class_schedule()
  1341.         read_in_schedule_data(config.prog_path + "schedule.csv")   
  1342.     else:  
  1343.         quit ( "No Schedule")
  1344.        
  1345.     if config.logging_on:
  1346.         pr(here, "Starting with Logging to : " + config.logging_filename + " at ", datetime.datetime.now())
  1347.     else:
  1348.         pr(here, "Starting with Logging Off at : " + datetime.datetime.now())
  1349.     if config.max_scans > 0:
  1350.         pr(here, "Starting Temp Sensor Scans for : " + str(config.max_scans) + " scans starting at : ", datetime.datetime.now())
  1351.     else:
  1352.         pr(here, "Starting Continuous Temp Sensor Scans for at : ", datetime.datetime.now())
  1353.     pr(here, "With an interval of : ", config.scan_delay)
  1354.    
  1355.    
  1356.  
  1357.     #Main Loop
  1358.     change_flag = False
  1359.     config.scan_count = 1
  1360.     config.sensor_present = False
  1361.     # Scan for max_scan times or for ever if config.max_scans = 0
  1362.     while (config.scan_count <= config.max_scans) or (config.max_scans == 0):
  1363.         # check_for_new codes and find out what sensors are cobnnected
  1364.         # geting new codes if there are any
  1365.         new_codes_count =get_temps()
  1366.        
  1367.         # then if there are any new we have not seen before write to the sensor file
  1368.         if new_codes_count >0 :
  1369.             write_sensor_data(new_codes_count,len(my_sensors.code) == new_codes_count)
  1370.  
  1371.         # now get data from all the sensor that are connected
  1372.        
  1373.         for z in range(0,len(my_sensors.code),1):
  1374.             if my_sensors.connected[z]:
  1375.                 pr_w1(here, "Scan Reached " + str(z), "connected status : " + str(my_sensors.connected[z]))
  1376.                 # if there has been a timeout value will be about 8 initially
  1377.                 #if (my_sensors.delay[z] < config.delay_limit):
  1378.                     # get_temperature(z)
  1379.                 pr_w1(here,"sensor : " + str(my_sensors.number[z]) + " returned :", my_sensors.reading[z])
  1380.                 #else:
  1381.         #           if my_sensors.delay[z] >= config.delay_limit:
  1382.         #               my_sensors.delay[z] -= config.delay_increment # so after few scans will try again
  1383.         #   else:
  1384.         #       my_sensors.delay[z] = 0
  1385.        
  1386.             # check if this sensor has changed more than 0.25 degrees, if so set flag
  1387.             # that will trigger print out and logging
  1388.        
  1389.             if (abs(my_sensors.last_logged[z] - my_sensors.reading[z])) > float(config.change4log):
  1390.                 change_flag = True
  1391.                 if config.scan_count > 1 :
  1392.        
  1393.                     # Following two Lines helps watching changes but is not needed
  1394.                     # pr_log(True,"Change detected in sensor : " + str(my_sensors.number[z]) + "was : " +
  1395.                     # str(my_sensors.last_logged[z]) + " now : " + str(my_sensors.reading[z]))
  1396.                     my_sensors.last_logged[z] = my_sensors.reading[z]
  1397.             if my_sensors.last_logged_error_number[z] != my_sensors.error_number[z]:
  1398.                 change_flag = True
  1399.  
  1400. # ****************************
  1401. #  Get target temperature
  1402. #****************************  
  1403.         time_now = datetime.datetime.now()
  1404.         if sauna:
  1405.             target_temp = config.default_target
  1406.         else:  
  1407.             target_temp = get_target_temp(time_now.year,time_now.month,time_now.day,time_now.hour,time_now.minute)
  1408.  
  1409. # ****************************
  1410. # Start of smartplug Control *
  1411. # ****************************
  1412.        
  1413.         #  Check if reading indictates if heaters should be turned on of off       
  1414.         between = False
  1415.         control_error = (my_sensors.reading[config.ref_sensor_index] - target_temp)/config.control_hysteresis
  1416.         if sauna :
  1417.             if (len(my_sensors.reading) > 0) and (config.ref_sensor_index != -1 ):
  1418.                 if sevenseg :
  1419.                     show_numbers(target_temp, my_sensors.reading[config.ref_sensor_index] )
  1420.                 if my_sensors.reading[config.ref_sensor_index] > target_temp + config.control_hysteresis :
  1421.                     GPIO.output(18, GPIO.LOW)
  1422.                     print("temp error to send is ", my_sensors.reading[config.ref_sensor_index] - target_temp, "100% off" )
  1423.                 else:
  1424.                     if my_sensors.reading[config.ref_sensor_index] < target_temp - config.control_hysteresis:
  1425.                         GPIO.output(18, GPIO.HIGH)
  1426.                         print("temp error to send is ", my_sensors.reading[config.ref_sensor_index] - target_temp, "100% on")
  1427.                     else:
  1428.                         between = True
  1429.                         sauna_on = min_on + (period-min_on)*((target_temp+config.control_hysteresis)-my_sensors.reading[config.ref_sensor_index])/(2*config.control_hysteresis)
  1430.                         if sauna_on <0 :
  1431.                             sauna_on = 0
  1432.                         sauna_off = period - sauna_on
  1433.                         if sauna_off < 0 :
  1434.                             sauna_off = 0
  1435.                         print("Error" , str(control_error), "  We are between.  On Time : " + str(sauna_on) + "  Off Time : " + str(sauna_off))
  1436.                         GPIO.output(18, GPIO.HIGH)
  1437.                         time.sleep(sauna_on)
  1438.                         if sauna_off > 0 :
  1439.                             GPIO.output(18, GPIO.LOW)
  1440.                             time.sleep(sauna_off)
  1441.             else:
  1442.                 print(  len(my_sensors.reading),  config.ref_sensor_index )
  1443.                 pr_status(True,0, "Cannot control no sensors or reference sensor not defined")
  1444.         else
  1445.             if (len(my_sensors.reading) > 0) and (config.ref_sensor_index != -1 ):
  1446.                
  1447.                 print("smartplug control temperatures being used", my_sensors.reading[config.ref_sensor_index], target_temp )
  1448.                
  1449.                 if my_sensors.reading[config.ref_sensor_index] > target_temp + float(config.control_hysteresis) :
  1450.                     pr_w1(here,"Turn off smart plugs at temp: ", my_sensors.reading[config.ref_sensor_index])
  1451.                     turn_off_smartplug(0)
  1452.                     turn_off_smartplug(1)
  1453.                 else:
  1454.                     if my_sensors.reading[config.ref_sensor_index] < target_temp - float(config.control_hysteresis) :
  1455.                         pr_w1(here,"Turn on smart plugs at temp : ", my_sensors.reading[config.ref_sensor_index])
  1456.                         turn_on_smartplug(0)
  1457.                         turn_on_smartplug(1)
  1458.             else:
  1459.                 pr_status(True,0, "Cannot control no sensors or reference sensor not defined")             
  1460.                
  1461. # ****************************
  1462. #  End  of smartplug Control *
  1463. # ****************************
  1464.  
  1465.         #for test only to get more print outs and logging
  1466.         #change_flag = True
  1467.  
  1468.        
  1469.         if change_flag or (config.scan_count == config.max_scans) or (config.scan_count == 0):
  1470.             # now if data changed do logging printing and sending
  1471.             set_status_text() # figure out the status text for the temperature sensors
  1472.             if config.logging_on:
  1473.                 log_temperature_data_to_file()
  1474.             if config.ftplog_count > config.ftplog :
  1475.            
  1476.                 ftp_result = send_by_ftp(config.ftp_credentials_log_filename, config.logging_filename, config.logging_filename_save_as)
  1477.                
  1478.                 for pres_ind in range(0,len(ftp_result)):
  1479.                     pr_f(here, str(pres_ind) + " : ",ftp_result[pres_ind])
  1480.                
  1481.                 try:
  1482.                     copyfile(config.logging_filename, config.local_www_log_csv)
  1483.                     # Uncoment following line for info on copying file to web site dir
  1484.                     pr_f( "Sent : "+ config.logging_filename + " to : " + config.local_www_log_csv)
  1485.                 except:
  1486.                     pr_status(True,0, "Fail with send log csv to " + config.local_www_log_csv)
  1487.            
  1488.                 config.ftplog_count = 0
  1489.            
  1490.             else:
  1491.                 config.ftplog_count = config.ftplog_count +1
  1492.  
  1493. # *******************************************************************************
  1494. #  After logging done, have all info send html file to websites done every scan *
  1495. # *******************************************************************************
  1496.         send_temperature_data_using_ftp(config.ftp_credentials_filename)
  1497.  
  1498.         if (len(my_sensors.reading) > 0):
  1499.             #must be some sensor before we can print data
  1500.             if debug:
  1501.                 #printouts if in debug
  1502.                 pr_log(True, "\n" + make_printout_for_screen(change_flag) + "\n")
  1503.             else:
  1504.                 if change_flag:
  1505.                     #printouts if not in debug and data changed
  1506.                     pr_log(True,make_printout_for_screen(change_flag))
  1507.                 else:
  1508.                     #printouts if not in debug and no data changed
  1509.                     pr_log(False,make_printout_for_screen(change_flag))
  1510.            
  1511. #reset change flag and operate delay before next scan
  1512.         change_flag = False
  1513.         last_ended  = make_time_text(datetime.datetime.now())  
  1514.         if not between :
  1515.             time.sleep(config.scan_delay)
  1516.         config.scan_count += 1
  1517.         # following line can be used
  1518.         pr_status(False,1,"Scan " + str(config.scan_count-1) + " ended at  " + last_ended + "  Now Start Scan : " + str(config.scan_count))
  1519.         pr(here, " ******** Scan Counting to " + str(config.max_scans) + "  now at scan " , config.scan_count)
  1520.     return 0
  1521.  
  1522. if __name__ == '__main__':
  1523.     main(sys.argv[1:])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement