Advertisement
Guest User

Full working order

a guest
Oct 19th, 2014
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 34.08 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. import sys, os
  4. import serial
  5. import time, datetime
  6. import threading, thread
  7. import socket
  8. from collections import deque
  9. import random
  10.  
  11. ##############################################################################
  12. #  pyRadMon - logger for Geiger counters                                     #
  13. #  Original Copyright 2013 by station pl_gdn_1                               #
  14. #  Copyright 2014 by Auseklis Corporation, Richmond, Virginia, U.S.A.        #
  15. #                                                                            #
  16. #  This file is part of The PyRadMon Project                                 #
  17. #  https://sourceforge.net/p/pyradmon                                        #
  18. #                                                                            #
  19. #  PyRadMon is free software: you can redistribute it and/or modify it under #
  20. #  the terms of the GNU General Public License as published by the Free      #
  21. #  Software Foundation, either version 3 of the License, or (at your option) #
  22. #  any later version.                                                        #
  23. #                                                                            #
  24. #  PyRadMon is distributed in the hope that it will be useful, but WITHOUT   #
  25. #  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     #
  26. #  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for #
  27. #  more details.                                                             #
  28. #                                                                            #
  29. #  You should have received a copy of the GNU General Public License         #
  30. #  along with PyRadMon.  If not, see <http://www.gnu.org/licenses/>.         #
  31. #                                                                            #
  32. #  @license GPL-3.0+ <http://spdx.org/licenses/GPL-3.0+>                     #
  33. ##############################################################################
  34. #  version is a.b.c, change in a or b means new functionality/bugfix,        #
  35. #  change in c = bugfix                                                      #
  36. #  do not uncomment line below, it's currently used in HTTP headers          #
  37. VERSION="0.5.6"
  38. #  To see your online los, report a bug or request a new feature, please     #
  39. #  visit http://www.radmon.org and/or https://sourceforge.net/p/pyradmon     #
  40. ##############################################################################
  41.  
  42.  
  43. ##############################################################################
  44. # Part 1 - configuration procedures
  45. #
  46. # Read configuration from file + constants definition
  47. ##############################################################################
  48. class config():
  49.     # used as enums
  50.     UNKNOWN=0
  51.     DEMO=1
  52.     MYGEIGER=2
  53.     GMC=3
  54.     NETIO=4
  55.  
  56.     def __init__(self):
  57.         # define constants
  58.         self.CONFIGFILE="config.txt"
  59.         self.UNKNOWN=0
  60.         self.DEMO=1
  61.         self.MYGEIGER=2
  62.         self.GMC=3
  63.         self.NETIO=4
  64.  
  65.         self.user="not_set"
  66.         self.password="not_set"
  67.  
  68.         self.portName=None
  69.         self.portSpeed=2400
  70.         self.timeout=40 # not used for now
  71.         self.protocol=self.UNKNOWN
  72.  
  73.     def readConfig(self):
  74.         print "Reading configuration:\r\n\t"
  75.  
  76.         # check if file exists, if not, create one and exit
  77.         if (os.path.isfile(self.CONFIGFILE)==0):
  78.             print "\tNo configuration file, creating default one.\r\n\t"
  79.  
  80.             try:
  81.                 f = open(self.CONFIGFILE, 'w')
  82.                 f.write("# Parameter names are not case-sensitive\r\n")
  83.                 f.write("# Parameter values are case-sensitive\r\n")
  84.                 f.write("user=test_user\r\n")
  85.                 f.write("password=test_password\r\n")
  86.                 f.write("# Port is usually /dev/ttyUSBx in Linux and COMx in Windows\r\n")
  87.                 f.write("serialport=/dev/ttyUSB0\r\n")
  88.                 f.write("speed=2400\r\n")
  89.                 f.write("# Protocols: demo, mygeiger, gmc, netio\r\n")
  90.                 f.write("protocol=demo\r\n")
  91.                 f.write("user2=test_user\r\n")
  92.                 f.write("password2=test_password\r\n")
  93.                 f.write("# Port is usually /dev/ttyUSBx in Linux and COMx in Windows\r\n")
  94.                 f.write("serialport2=/dev/ttyUSB1\r\n")
  95.                 f.write("speed2=2400\r\n")
  96.                 f.write("# Protocols: demo, mygeiger, gmc, netio\r\n")
  97.                 f.write("protocol2=demo\r\n")
  98.                 f.close()
  99.                 exit(1)
  100.                 print "\tPlease open config.txt file using text editor and update configuration.\r\n"
  101.             except Exception as e:
  102.                 print "\tFailed to create configuration file\r\n\t",str(e)
  103.             exit(1)
  104.  
  105.         # if file is present then try to read configuration from it
  106.         try:
  107.             f = open(self.CONFIGFILE)
  108.             line=" "
  109.             # analyze file line by line, format is parameter=value
  110.             while (line):
  111.                 line=f.readline()
  112.                 params=line.split("=")
  113.  
  114.                 if len(params)==2:
  115.                     parameter=params[0].strip().lower()
  116.                     value=params[1].strip()
  117.                    
  118.                     if parameter=="user":
  119.                         self.user=value
  120.                         print "\tUser name configured\r\n\t"
  121.  
  122.                     elif parameter=="password":
  123.                         self.password=value
  124.                         print "\tPassword configured\r\n\t"
  125.  
  126.                     elif parameter=="serialport":
  127.                         self.portName=value
  128.                         print "\tSerial port name configured\r\n\t"
  129.  
  130.                     elif parameter=="speed":
  131.                         self.portSpeed=int(value)
  132.                         print "\tSerial port speed configured\r\n\t"
  133.  
  134.                     elif parameter=="protocol":
  135.                         value=value.lower()
  136.                         if value=="mygeiger":
  137.                             self.protocol=self.MYGEIGER
  138.                         elif value=="demo":
  139.                             self.protocol=self.DEMO
  140.                         elif value=="gmc":
  141.                             self.protocol=self.GMC
  142.                         elif value=="netio":
  143.                             self.protocol=self.NETIO
  144.  
  145.                         if self.protocol!=self.UNKNOWN:
  146.                             print "\tProtocol configured\r\n\t"
  147.                 # end of if
  148.             # end of while
  149.             f.close()
  150.         except Exception as e:
  151.             print "\tFailed to read configuration file:\r\n\t",str(e), "\r\nExiting\r\n"
  152.             exit(1)
  153.         # well done, configuration is ready to use
  154.         print ""
  155.  
  156. class config2():
  157.     # used as enums
  158.     UNKNOWN=0
  159.     DEMO=1
  160.     MYGEIGER=2
  161.     GMC=3
  162.     NETIO=4
  163.  
  164.     def __init__(self):
  165.         # define constants
  166.         self.CONFIGFILE="config.txt"
  167.         self.UNKNOWN=0
  168.         self.DEMO=1
  169.         self.MYGEIGER=2
  170.         self.GMC=3
  171.         self.NETIO=4
  172.  
  173.         self.user="not_set"
  174.         self.password="not_set"
  175.  
  176.         self.portName=None
  177.         self.portSpeed=2400
  178.         self.timeout=40 # not used for now
  179.         self.protocol=self.UNKNOWN
  180.  
  181.     def readConfig(self):
  182.         print "Reading configuration:\r\n\t"
  183.  
  184.         # if file is present then try to read configuration from it
  185.         try:
  186.             f = open(self.CONFIGFILE)
  187.             line=" "
  188.             # analyze file line by line, format is parameter=value
  189.             while (line):
  190.                 line=f.readline()
  191.                 params=line.split("=")
  192.  
  193.                 if len(params)==2:
  194.                     parameter=params[0].strip().lower()
  195.                     value=params[1].strip()
  196.                    
  197.                     if parameter=="user2":
  198.                         self.user=value
  199.                         print "\tUser name configured\r\n\t"
  200.  
  201.                     elif parameter=="password2":
  202.                         self.password=value
  203.                         print "\tPassword configured\r\n\t"
  204.  
  205.                     elif parameter=="serialport2":
  206.                         self.portName=value
  207.                         print "\tSerial port name configured\r\n\t"
  208.  
  209.                     elif parameter=="speed2":
  210.                         self.portSpeed=int(value)
  211.                         print "\tSerial port speed configured\r\n\t"
  212.  
  213.                     elif parameter=="protocol2":
  214.                         value=value.lower()
  215.                         if value=="mygeiger":
  216.                             self.protocol=self.MYGEIGER
  217.                         elif value=="demo":
  218.                             self.protocol=self.DEMO
  219.                         elif value=="gmc":
  220.                             self.protocol=self.GMC
  221.                         elif value=="netio":
  222.                             self.protocol=self.NETIO
  223.  
  224.                         if self.protocol!=self.UNKNOWN:
  225.                             print "\tProtocol configured\r\n\t"
  226.                 # end of if
  227.             # end of while
  228.             f.close()
  229.         except Exception as e:
  230.             print "\tFailed to read configuration file:\r\n\t",str(e), "\r\nExiting\r\n"
  231.             exit(1)
  232.         # well done, configuration is ready to use
  233.         print ""
  234.  
  235. ################################################################################
  236. # Part 2 - Geiger counter communication
  237. #
  238. # It should be easy to add different protocol by simply
  239. # creating new class based on baseGeigerCommunication, as it's done in
  240. # classes Demo and myGeiger
  241. ################################################################################
  242.  
  243. class baseGeigerCommunication(threading.Thread):
  244.  
  245.     def __init__(self, cfg):
  246.         super(baseGeigerCommunication, self).__init__()
  247.         self.sPortName=cfg.portName
  248.         self.sPortSpeed=cfg.portSpeed
  249.         self.timeout=cfg.timeout
  250.         self.stopwork=0
  251.         self.queue=deque()
  252.         self.queueLock=0
  253.         self.is_running=1
  254.  
  255.     def run(self):
  256.         try:
  257.             print "Gathering data started => geiger 1\r\n"
  258.             self.serialPort = serial.Serial(self.sPortName, self.sPortSpeed, timeout=1)
  259.             self.serialPort.flushInput()
  260.            
  261.             self.initCommunication()
  262.  
  263.             while(self.stopwork==0):
  264.                 result=self.getData()
  265.                 while (self.queueLock==1):
  266.                     print "Geiger communication: quene locked! => geiger 1\r\n"
  267.                     time.sleep(0.5)
  268.                 self.queueLock=1
  269.                 self.queue.append(result)
  270.                 self.queueLock=0
  271.                 print "Geiger sample => geiger 1:\tCPM =",result[0],"\t",str(result[1])
  272.  
  273.             self.serialPort.close()
  274.             print "Gathering data from Geiger stopped => geiger 1\r\n"
  275.         except serial.SerialException as e:
  276.             print "Problem with serial port => geiger 1:\r\n\t", str(e),"\r\nExiting\r\n"
  277.             self.stop()
  278.             sys.exit(1)
  279.  
  280.     def initCommunication(self):
  281.         print "Initializing geiger communication => geiger 1\r\n"
  282.  
  283.     def sendCommand(self, command):
  284.         self.serialPort.flushInput()
  285.         self.serialPort.write(command)
  286.         # assume that device responds within 0.5s
  287.         time.sleep(0.5)
  288.         response=""
  289.         while (self.serialPort.inWaiting()>0 and self.stopwork==0):
  290.             response = response + self.serialPort.read()
  291.         return response
  292.  
  293.     def getData(self):
  294.         cpm=25
  295.         utcTime=datetime.datetime.utcnow()
  296.         data=[cpm, utcTime]
  297.         return data
  298.  
  299.     def stop(self):
  300.         self.stopwork=1
  301.         self.queueLock=0
  302.         self.is_running=0
  303.  
  304.     def getResult(self):
  305.         # check if we have some data in queue
  306.         if len(self.queue)>0:
  307.  
  308.             # check if it's safe to process queue
  309.             while (self.queueLock==1):
  310.                 print "getResult: quene locked! => geiger 1\r\n"
  311.                 time.sleep(0.5)
  312.  
  313.             # put lock so measuring process will not interfere with queue,
  314.             # processing should be fast enought to not break data acquisition from geiger
  315.             self.queueLock=1
  316.  
  317.             cpm=0
  318.             # now get sum of all CPM's
  319.             for singleData in self.queue:
  320.                 cpm=cpm+singleData[0]
  321.  
  322.             # and divide by number of elements
  323.             # to get mean value, 0.5 is for rounding up/down
  324.             cpm=int( ( float(cpm) / len(self.queue) ) +0.5)
  325.             # report with latest time from quene
  326.             utcTime=self.queue.pop()[1]
  327.  
  328.             # clear queue and remove lock
  329.             self.queue.clear()
  330.             self.queueLock=0
  331.  
  332.             data=[cpm, utcTime]
  333.         else:
  334.             # no data in queue, return invalid CPM data and current time
  335.             data=[-1, datetime.datetime.utcnow()]
  336.  
  337.         return data
  338.  
  339. class Demo(baseGeigerCommunication):
  340.  
  341.     def run(self):
  342.         print "Gathering data started => geiger 1\r\n"
  343.  
  344.         while(self.stopwork==0):
  345.             result=self.getData()
  346.             while (self.queueLock==1):
  347.                 print "Geiger communication: quene locked! => geiger 1\r\n"
  348.                 time.sleep(0.5)
  349.             self.queueLock=1
  350.             self.queue.append(result)
  351.             self.queueLock=0
  352.             print "Geiger sample => geiger 1:\t",result,"\r\n"
  353.  
  354.         print "Gathering data from Geiger stopped => geiger 1\r\n"
  355.  
  356.     def getData(self):
  357.         for i in range(0,5):
  358.             time.sleep(1)
  359.         cpm=random.randint(5,40)
  360.         utcTime=datetime.datetime.utcnow()
  361.         data=[cpm, utcTime]
  362.         return data
  363.  
  364. class myGeiger(baseGeigerCommunication):
  365.  
  366.     def getData(self):
  367.         cpm=-1
  368.         try:
  369.             # wait for data
  370.             while (self.serialPort.inWaiting()==0 and self.stopwork==0):
  371.                 time.sleep(1)
  372.  
  373.             time.sleep(0.1) # just to ensure all CPM bytes are in serial port buffer
  374.             # read all available data
  375.             x=""
  376.             while (self.serialPort.inWaiting()>0 and self.stopwork==0):
  377.                 x = x + self.serialPort.read()
  378.  
  379.             if len(x)>0:
  380.                 cpm=int(x)
  381.  
  382.             utcTime=datetime.datetime.utcnow()
  383.             data=[cpm, utcTime]
  384.             return data
  385.         except Exception as e:
  386.             print "\r\nProblem in getData procedure (disconnected USB device?) => geiger 1:\r\n\t",str(e),"\r\nExiting\r\n"
  387.             self.stop()
  388.             sys.exit(1)
  389.  
  390. class gmc(baseGeigerCommunication):
  391.  
  392.     def initCommunication(self):
  393.        
  394.         print "Initializing GMC protocol communication => geiger 1\r\n"
  395.         # get firmware version
  396.         response=self.sendCommand("<GETVER>>")
  397.        
  398.         if len(response)>0:
  399.             print "Found GMC-compatible device, version => geiger 1: ", response, "\r\n"
  400.             # get serial number
  401.             # serialnum=self.sendCommand("<GETSERIAL>>")
  402.             # serialnum.int=struct.unpack('!1H', serialnum(7))[0]
  403.             # print "Device Serial Number is: ", serialnum.int
  404.             # disable heartbeat, we will request data from script
  405.             self.sendCommand("<HEARTBEAT0>>")
  406.             print "Please note data will be acquired once per 5 seconds => geiger 1\r\n"
  407.             # update the device time
  408.             unitTime=self.sendCommand("<GETDATETIME>>")
  409.             print "Unit shows time as => geiger 1: ", unitTime, "\r\n"
  410.             # self.sendCommand("<SETDATETIME[" + time.strftime("%y%m%d%H%M%S") + "]>>")
  411.             print "<SETDATETIME[" + time.strftime("%y%m%d%H%M%S") + "]>>"
  412.  
  413.         else:
  414.             print "No response from device => geiger 1\r\n"
  415.             self.stop()
  416.             sys.exit(1)
  417.  
  418.     def getData(self):
  419.         cpm=-1
  420.         try:
  421.             # wait, we want sample every 30s
  422.             for i in range(0,3):
  423.                 time.sleep(1)
  424.            
  425.             # send request
  426.             response=self.sendCommand("<GETCPM>>")
  427.            
  428.             if len(response)==2:
  429.                 # convert bytes to 16 bit int
  430.                 cpm=ord(response[0])*256+ord(response[1])
  431.             else:
  432.                 print "Unknown response to CPM request, device is not GMC-compatible? => geiger 1\r\n"
  433.                 self.stop()
  434.                 sys.exit(1)
  435.                
  436.             utcTime=datetime.datetime.utcnow()
  437.             data=[cpm, utcTime]
  438.             return data
  439.            
  440.         except Exception as e:
  441.             print "\r\nProblem in getData procedure (disconnected USB device?) => geiger 1:\r\n\t",str(e),"\r\nExiting\r\n"
  442.             self.stop()
  443.             sys.exit(1)
  444.  
  445. class netio(baseGeigerCommunication):
  446.  
  447.     def getData(self):
  448.         cpm=-1
  449.         try:
  450.             # we want data only once per 30 seconds, ignore rest
  451.             # it's averaged for 60 seconds by device anyway
  452.             for i in range(0,30):
  453.                 time.sleep(1)
  454.  
  455.             # wait for data, should be already there (from last 30s)
  456.             while (self.serialPort.inWaiting()==0 and self.stopwork==0):
  457.                 time.sleep(0.5)
  458.            
  459.             time.sleep(0.1) # just to ensure all CPM bytes are in serial port buffer
  460.             # read all available data
  461.  
  462.             # do not stop receiving unless it ends with \r\n
  463.             x=""
  464.             while ( x.endswith("\r\n")==False and self.stopwork==0):
  465.                 while ( self.serialPort.inWaiting()>0 and self.stopwork==0 ):
  466.                     x = x + self.serialPort.read()
  467.  
  468.             # if CTRL+C pressed then x can be invalid so check it
  469.             if x.endswith("\r\n"):
  470.                 # we want only latest data, ignore older
  471.                 tmp=x.splitlines()
  472.                 x=tmp[len(tmp)-1]
  473.                 cpm=int(x)
  474.            
  475.             utcTime=datetime.datetime.utcnow()
  476.             data=[cpm, utcTime]
  477.             return data
  478.  
  479.         except Exception as e:
  480.             print "\r\nProblem in getData procedure (disconnected USB device?) => geiger 1:\r\n\t",str(e),"\r\nExiting\r\n"
  481.             self.stop()
  482.             sys.exit(1)
  483.  
  484.     def initCommunication(self):
  485.         print "Initializing NetIO => geiger 1\r\n"
  486.         # send "go" to start receiving CPM data
  487.         response=self.sendCommand("go\r\n")
  488.         print "Please note data will be acquired once per 30 seconds => geiger 1\r\n"
  489.  
  490. class baseGeigerCommunication2(threading.Thread):
  491.  
  492.     def __init__(self, cfg2):
  493.         super(baseGeigerCommunication2, self).__init__()
  494.         self.sPortName=cfg2.portName
  495.         self.sPortSpeed=cfg2.portSpeed
  496.         self.timeout=cfg2.timeout
  497.         self.stopwork=0
  498.         self.queue=deque()
  499.         self.queueLock=0
  500.         self.is_running=1
  501.  
  502.     def run(self):
  503.         try:
  504.             print "Gathering data started => geiger 2\r\n"
  505.             self.serialPort = serial.Serial(self.sPortName, self.sPortSpeed, timeout=1)
  506.             self.serialPort.flushInput()
  507.            
  508.             self.initCommunication()
  509.  
  510.             while(self.stopwork==0):
  511.                 result=self.getData()
  512.                 while (self.queueLock==1):
  513.                     print "Geiger communication: quene locked! => geiger 2\r\n"
  514.                     time.sleep(0.5)
  515.                 self.queueLock=1
  516.                 self.queue.append(result)
  517.                 self.queueLock=0
  518.                 print "Geiger sample => geiger 2:\tCPM =",result[0],"\t",str(result[1]),"\r\n"
  519.  
  520.             self.serialPort.close()
  521.             print "Gathering data from Geiger stopped => geiger 2\r\n"
  522.         except serial.SerialException as e:
  523.             print "Problem with serial port => geiger 2:\r\n\t", str(e),"\r\nExiting\r\n"
  524.             self.stop()
  525.             sys.exit(1)
  526.  
  527.     def initCommunication(self):
  528.         print "Initializing geiger communication => geiger 2\r\n"
  529.  
  530.     def sendCommand(self, command):
  531.         self.serialPort.flushInput()
  532.         self.serialPort.write(command)
  533.         # assume that device responds within 0.5s
  534.         time.sleep(0.5)
  535.         response=""
  536.         while (self.serialPort.inWaiting()>0 and self.stopwork==0):
  537.             response = response + self.serialPort.read()
  538.         return response
  539.  
  540.     def getData(self):
  541.         cpm=25
  542.         utcTime=datetime.datetime.utcnow()
  543.         data=[cpm, utcTime]
  544.         return data
  545.  
  546.     def stop(self):
  547.         self.stopwork=1
  548.         self.queueLock=0
  549.         self.is_running=0
  550.  
  551.     def getResult(self):
  552.         # check if we have some data in queue
  553.         if len(self.queue)>0:
  554.  
  555.             # check if it's safe to process queue
  556.             while (self.queueLock==1):
  557.                 print "getResult: quene locked! => geiger 2\r\n"
  558.                 time.sleep(0.5)
  559.  
  560.             # put lock so measuring process will not interfere with queue,
  561.             # processing should be fast enought to not break data acquisition from geiger
  562.             self.queueLock=1
  563.  
  564.             cpm=0
  565.             # now get sum of all CPM's
  566.             for singleData in self.queue:
  567.                 cpm=cpm+singleData[0]
  568.  
  569.             # and divide by number of elements
  570.             # to get mean value, 0.5 is for rounding up/down
  571.             cpm=int( ( float(cpm) / len(self.queue) ) +0.5)
  572.             # report with latest time from quene
  573.             utcTime=self.queue.pop()[1]
  574.  
  575.             # clear queue and remove lock
  576.             self.queue.clear()
  577.             self.queueLock=0
  578.  
  579.             data=[cpm, utcTime]
  580.         else:
  581.             # no data in queue, return invalid CPM data and current time
  582.             data=[-1, datetime.datetime.utcnow()]
  583.  
  584.         return data
  585.  
  586. class Demo2(baseGeigerCommunication2):
  587.  
  588.     def run(self):
  589.         print "Gathering data started => geiger 2\r\n"
  590.  
  591.         while(self.stopwork==0):
  592.             result=self.getData()
  593.             while (self.queueLock==1):
  594.                 print "Geiger communication: quene locked! => geiger 2\r\n"
  595.                 time.sleep(0.5)
  596.             self.queueLock=1
  597.             self.queue.append(result)
  598.             self.queueLock=0
  599.             print "Geiger sample => geiger 2:\t",result,"\r\n"
  600.  
  601.         print "Gathering data from Geiger stopped => geiger 2\r\n"
  602.  
  603.     def getData(self):
  604.         for i in range(0,5):
  605.             time.sleep(1)
  606.         cpm=random.randint(5,40)
  607.         utcTime=datetime.datetime.utcnow()
  608.         data=[cpm, utcTime]
  609.         return data
  610.  
  611. class myGeiger2(baseGeigerCommunication2):
  612.  
  613.     def getData(self):
  614.         cpm=-1
  615.         try:
  616.             # wait for data
  617.             while (self.serialPort.inWaiting()==0 and self.stopwork==0):
  618.                 time.sleep(1)
  619.  
  620.             time.sleep(0.1) # just to ensure all CPM bytes are in serial port buffer
  621.             # read all available data
  622.             x=""
  623.             while (self.serialPort.inWaiting()>0 and self.stopwork==0):
  624.                 x = x + self.serialPort.read()
  625.  
  626.             if len(x)>0:
  627.                 cpm=int(x)
  628.  
  629.             utcTime=datetime.datetime.utcnow()
  630.             data=[cpm, utcTime]
  631.             return data
  632.         except Exception as e:
  633.             print "\r\nProblem in getData procedure (disconnected USB device?) => geiger 2:\r\n\t",str(e),"\r\nExiting\r\n"
  634.             self.stop()
  635.             sys.exit(1)
  636.  
  637. class gmc2(baseGeigerCommunication2):
  638.  
  639.     def initCommunication(self):
  640.        
  641.         print "Initializing GMC protocol communication => geiger 2\r\n"
  642.         # get firmware version
  643.         response=self.sendCommand("<GETVER>>")
  644.        
  645.         if len(response)>0:
  646.             print "Found GMC-compatible device, version => geiger 2: ", response, "\r\n"
  647.             # get serial number
  648.             # serialnum=self.sendCommand("<GETSERIAL>>")
  649.             # serialnum.int=struct.unpack('!1H', serialnum(7))[0]
  650.             # print "Device Serial Number is: ", serialnum.int
  651.             # disable heartbeat, we will request data from script
  652.             self.sendCommand("<HEARTBEAT0>>")
  653.             print "Please note data will be acquired once per 5 seconds => geiger 2\r\n"
  654.             # update the device time
  655.             unitTime=self.sendCommand("<GETDATETIME>>")
  656.             print "Unit shows time as => geiger 2: ", unitTime, "\r\n"
  657.             # self.sendCommand("<SETDATETIME[" + time.strftime("%y%m%d%H%M%S") + "]>>")
  658.             print "<SETDATETIME[" + time.strftime("%y%m%d%H%M%S") + "]>>"
  659.  
  660.         else:
  661.             print "No response from device => geiger 2\r\n"
  662.             self.stop()
  663.             sys.exit(1)
  664.  
  665.     def getData(self):
  666.         cpm=-1
  667.         try:
  668.             # wait, we want sample every 30s
  669.             for i in range(0,3):
  670.                 time.sleep(1)
  671.            
  672.             # send request
  673.             response=self.sendCommand("<GETCPM>>")
  674.            
  675.             if len(response)==2:
  676.                 # convert bytes to 16 bit int
  677.                 cpm=ord(response[0])*256+ord(response[1])
  678.             else:
  679.                 print "Unknown response to CPM request, device is not GMC-compatible? => geiger 2\r\n"
  680.                 self.stop()
  681.                 sys.exit(1)
  682.                
  683.             utcTime=datetime.datetime.utcnow()
  684.             data=[cpm, utcTime]
  685.             return data
  686.            
  687.         except Exception as e:
  688.             print "\r\nProblem in getData procedure (disconnected USB device?) => geiger 2:\r\n\t",str(e),"\r\nExiting\r\n"
  689.             self.stop()
  690.             sys.exit(1)
  691.  
  692. class netio2(baseGeigerCommunication2):
  693.  
  694.     def getData(self):
  695.         cpm=-1
  696.         try:
  697.             # we want data only once per 30 seconds, ignore rest
  698.             # it's averaged for 60 seconds by device anyway
  699.             for i in range(0,30):
  700.                 time.sleep(1)
  701.  
  702.             # wait for data, should be already there (from last 30s)
  703.             while (self.serialPort.inWaiting()==0 and self.stopwork==0):
  704.                 time.sleep(0.5)
  705.            
  706.             time.sleep(0.1) # just to ensure all CPM bytes are in serial port buffer
  707.             # read all available data
  708.  
  709.             # do not stop receiving unless it ends with \r\n
  710.             x=""
  711.             while ( x.endswith("\r\n")==False and self.stopwork==0):
  712.                 while ( self.serialPort.inWaiting()>0 and self.stopwork==0 ):
  713.                     x = x + self.serialPort.read()
  714.  
  715.             # if CTRL+C pressed then x can be invalid so check it
  716.             if x.endswith("\r\n"):
  717.                 # we want only latest data, ignore older
  718.                 tmp=x.splitlines()
  719.                 x=tmp[len(tmp)-1]
  720.                 cpm=int(x)
  721.            
  722.             utcTime=datetime.datetime.utcnow()
  723.             data=[cpm, utcTime]
  724.             return data
  725.  
  726.         except Exception as e:
  727.             print "\r\nProblem in getData procedure (disconnected USB device?) => geiger 2:\r\n\t",str(e),"\r\nExiting\r\n"
  728.             self.stop()
  729.             sys.exit(1)
  730.  
  731.     def initCommunication(self):
  732.         print "Initializing NetIO => geiger 2\r\n"
  733.         # send "go" to start receiving CPM data
  734.         response=self.sendCommand("go\r\n")
  735.         print "Please note data will be acquired once per 30 seconds => geiger 2\r\n"
  736.  
  737. ################################################################################
  738. # Part 3 - Web server communication
  739. ################################################################################
  740. class webCommunication():
  741.     HOST="www.radmon.org"
  742.     #HOST="127.0.0.1" # uncomment this for debug purposes on localhost
  743.     PORT=80
  744.  
  745.     def __init__(self, mycfg):
  746.         self.user=mycfg.user
  747.         self.password=mycfg.password
  748.  
  749.     def sendSample(self, sample):
  750.  
  751.         print "Connecting to server => geiger 1\r\n"
  752.         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  753.         s.connect((self.HOST, self.PORT))
  754.  
  755.         BUFFER_SIZE=1024
  756.  
  757.         sampleCPM=sample[0]
  758.         sampleTime=sample[1]
  759.  
  760.         # format date and time as required
  761.         dtime=sampleTime.strftime("%Y-%m-%d%%20%H:%M:%S")
  762.  
  763.         url="GET /radmon.php?user="+self.user+"&password="+self.password+"&function=submit&datetime="+dtime+"&value="+str(sampleCPM)+"&unit=CPM HTTP/1.1"
  764.  
  765.         request=url+"\r\nHost: www.radmon.org\r\nUser-Agent: pyRadMon "+VERSION+"\r\n\r\n"
  766.         print "Sending average sample => geiger 1: "+str(sampleCPM)+" CPM\r\n"
  767.         #print "\r\n### HTTP Request ###\r\n"+request
  768.  
  769.         s.send(request)
  770.         data = s.recv(BUFFER_SIZE)
  771.         httpResponse=str(data).splitlines()[0]
  772.         print "Server response => geiger 1: ",httpResponse,"\r\n"
  773.  
  774.         if "incorrect login" in data.lower():
  775.             print "You are using incorrect user/password combination => geiger 1!\r\n"
  776.             geigerCommunication.stop()
  777.             geigerCommunication2.stop()
  778.             sys.exit(1)
  779.            
  780.         #print "\r\n### HTTP Response ###\r\n"+data+"\r\n"
  781.         s.close
  782.  
  783. class webCommunication2():
  784.     HOST="www.radmon.org"
  785.     #HOST="127.0.0.1" # uncomment this for debug purposes on localhost
  786.     PORT=80
  787.  
  788.     def __init__(self, mycfg):
  789.         self.user=mycfg.user
  790.         self.password=mycfg.password
  791.  
  792.     def sendSample(self, sample):
  793.  
  794.         print "Connecting to server => geiger 2\r\n"
  795.         s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  796.         s2.connect((self.HOST, self.PORT))
  797.  
  798.         BUFFER_SIZE=1024
  799.  
  800.         sampleCPM=sample[0]
  801.         sampleTime=sample[1]
  802.  
  803.         # format date and time as required
  804.         dtime=sampleTime.strftime("%Y-%m-%d%%20%H:%M:%S")
  805.  
  806.         url="GET /radmon.php?user="+self.user+"&password="+self.password+"&function=submit&datetime="+dtime+"&value="+str(sampleCPM)+"&unit=CPM HTTP/1.1"
  807.  
  808.         request=url+"\r\nHost: www.radmon.org\r\nUser-Agent: pyRadMon "+VERSION+"\r\n\r\n"
  809.         print "Sending average sample => geiger 2: "+str(sampleCPM)+" CPM\r\n"
  810.         #print "\r\n### HTTP Request ###\r\n"+request
  811.  
  812.         s2.send(request)
  813.         data = s2.recv(BUFFER_SIZE)
  814.         httpResponse=str(data).splitlines()[0]
  815.         print "Server response => geiger 2: ",httpResponse,"\r\n"
  816.  
  817.         if "incorrect login" in data.lower():
  818.             print "You are using incorrect user/password combination! => geiger 2\r\n"
  819.             geigerCommunication.stop()
  820.             geigerCommunication2.stop()
  821.             sys.exit(1)
  822.            
  823.         #print "\r\n### HTTP Response ###\r\n"+data+"\r\n"
  824.         s2.close
  825.  
  826.  
  827. ################################################################################
  828. # Main code
  829. ################################################################################
  830.  
  831. # create and read configuration data
  832. cfg=config()
  833. cfg.readConfig()
  834.  
  835. # create geiger communication object
  836. if cfg.protocol==config.MYGEIGER:
  837.     print "Using myGeiger protocol for 1 => geiger 1\r\n"
  838.     geigerCommunication=myGeiger(cfg)
  839. elif cfg.protocol==config.DEMO:
  840.     print "Using Demo mode for 1 => geiger 1\r\n"
  841.     geigerCommunication=Demo(cfg)
  842. elif cfg.protocol==config.GMC:
  843.     print "Using GMC protocol for 1 => geiger 1\r\n"
  844.     geigerCommunication=gmc(cfg)
  845. elif cfg.protocol==config.NETIO:
  846.     print "Using NetIO protocol for 1 => geiger 1\r\n"
  847.     geigerCommunication=netio(cfg)
  848. else:
  849.     print "Unknown protocol configured, can't run => geiger 1\r\n"
  850.     sys.exit(1)
  851.    
  852. # create and read configuration 2 data
  853. cfg2=config2()
  854. cfg2.readConfig()
  855.  
  856. if cfg2.protocol==config2.MYGEIGER:
  857.     print "Using myGeiger protocol => geiger 2\r\n"
  858.     geigerCommunication2=myGeiger2(cfg2)
  859. elif cfg2.protocol==config2.DEMO:
  860.     print "Using Demo mode => geiger 2\r\n"
  861.     geigerCommunication2=Demo2(cfg2)
  862. elif cfg2.protocol==config2.GMC:
  863.     print "Using GMC protocol => geiger 2\r\n"
  864.     geigerCommunication2=gmc2(cfg2)
  865. elif cfg2.protocol==config2.NETIO:
  866.     print "Using NetIO protocol => geiger 2\r\n"
  867.     geigerCommunication2=netio2(cfg2)
  868. else:
  869.     print "Unknown protocol configured, can't run => geiger 2\r\n"
  870.     sys.exit(1)
  871.  
  872. # create web server communication object
  873. webService=webCommunication(cfg)
  874. webService2=webCommunication2(cfg2)
  875.  
  876. # main loop is in while loop
  877. try:
  878.     # start measuring thread
  879.     geigerCommunication.start()
  880.     time.sleep(3)
  881.     geigerCommunication2.start()
  882.  
  883.     # Now send data to web site every 30 seconds
  884.     while(geigerCommunication.is_running==1 and geigerCommunication2.is_running==1):
  885.         sample=geigerCommunication.getResult()
  886.         sample2=geigerCommunication2.getResult()
  887.  
  888.         if sample[0]!=-1:
  889.             # sample is valid, CPM !=-1
  890.             print "Average result => geiger 1:\tCPM =",sample[0],"\t",str(sample[1]),"\r\n"
  891.             try:
  892.                 webService.sendSample(sample)
  893.             except Exception as e:
  894.                 print "Error communicating server => geiger 1:\r\n\t", str(e),"\r\n"
  895.  
  896.             print "Waiting 30 seconds => geiger 1\r\n"
  897.             # actually waiting 30x1 seconds, it's has better response when CTRL+C is used, maybe will be changed in future
  898.             for i in range(0,30):
  899.                 time.sleep(1)
  900.         else:
  901.             print "No samples in queue, waiting 5 seconds => geiger 1\r\n"
  902.             for i in range(0,5):
  903.                 time.sleep(1)
  904.  
  905.         if sample2[0]!=-1:
  906.             # sample2 is valid, CPM !=-1
  907.             print "Average result => geiger 2:\tCPM =",sample2[0],"\t",str(sample2[1]),"\r\n"
  908.             try:
  909.                 webService2.sendSample(sample2)
  910.             except Exception as e:
  911.                 print "Error communicating server => geiger 2:\r\n\t", str(e),"\r\n"
  912.  
  913.             print "Waiting 30 seconds => geiger 2\r\n"
  914.             # actually waiting 30x1 seconds, it's has better response when CTRL+C is used, maybe will be changed in future
  915.             for i in range(0,30):
  916.                 time.sleep(1)
  917.         else:
  918.             print "No samples in queue, waiting 5 seconds => geiger 2\r\n"
  919.             for i in range(0,5):
  920.                 time.sleep(1)
  921.  
  922. except KeyboardInterrupt as e:
  923.     print "\r\nCTRL+C pressed, exiting program\r\n\t", str(e), "\r\n"
  924.     geigerCommunication.stop()
  925.     geigerCommunication2.stop()
  926.  
  927. except Exception as e:
  928.     geigerCommunication.stop()
  929.     geigerCommunication2.stop()
  930.     print "\r\nUnhandled error\r\n\t",str(e),"\r\n"
  931.  
  932. geigerCommunication.stop()
  933. geigerCommunication2.stop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement