Advertisement
Guest User

Untitled

a guest
Nov 17th, 2017
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.13 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. from twisted.internet import protocol, defer, reactor
  3. from twisted.internet.serialport import SerialPort
  4. from twisted.internet.threads import deferToThread
  5. from twisted.web import server, resource
  6. from twisted.python.runtime import platform
  7. from twisted.python import log
  8. from twisted.enterprise import adbapi
  9. from twisted.web.static import File,DirectoryLister
  10. from twisted.web.util import redirectTo
  11. import json
  12. import sys
  13. import os
  14. import datetime
  15. import itertools
  16. from buffer import LineBuffer, UntillBuffer, Listener, BytesBuffer
  17. from subprocess import Popen, PIPE
  18. import collections
  19. import serial
  20. import xml.etree.ElementTree as etree
  21.  
  22. import time
  23.  
  24. try:
  25.     import ujson as json
  26. except:
  27.     import json
  28.  
  29. log.startLogging(sys.stdout)
  30.  
  31. #class impl temerature log with method for work with data
  32. class TempLog:
  33.     def __init__(self):
  34.         self.db = adbapi.ConnectionPool("sqlite3", "log.db", check_same_thread=False)
  35.        
  36.     def init_db(self):
  37.         return self.db.runQuery("CREATE TABLE IF NOT EXISTS temp_log (sensor_id TEXT, temp TEXT, date_log DATETIME DEFAULT CURRENT_TIMESTAMP)")
  38.  
  39.     def update(self, id, t):
  40.         self.db.runOperation("INSERT INTO temp_log (sensor_id, temp) VALUES(?,?)",(id,t))
  41.        
  42.     @defer.inlineCallbacks
  43.     def get_history(self, date = "now",modify="'%Y-%m-%d'", condition = ""):
  44.         '''
  45.         @date : actual data, for which measurents are taken
  46.         @modify: sort indiction for the period
  47.         @condition: ??? for feature
  48.         '''
  49.         if condition:
  50.             condition = "AND "+condition
  51.         res = yield self.db.runQuery("SELECT sensor_id, temp,log_date FROM temp_log WHERE strftime({modify},log_date) = strftime({modify},?) {condition}".format(modify= modify, condition = condition), (date,))
  52.         result =  collections.defaultdict(list)
  53.         for sens, temp, _date in res:
  54.             result[sens].append((_date,temp))
  55.    
  56.         for kk  in result.keys():
  57.             result[kk] = sorted(result[kk])
  58.         defer.returnValue(result)
  59.        
  60.     def get_average_by_sensor(self, sensor, modify):
  61.         '''
  62.         This method created for get averages data days, weeks, months, years and compare it.
  63.         '''
  64.         pass
  65.  
  66.  
  67.  
  68. def sleep(seconds):
  69.     d = defer.Deferred()
  70.     reactor.callLater(seconds, d.callback, seconds)
  71.     return d
  72.  
  73.  
  74.    
  75. class CronLog:
  76.     INTERVAL = 15*60
  77.     def __init__(self, log):
  78.         self._log = log
  79.         self.last_update = None
  80.         self._logged = 0
  81.    
  82.  
  83.    
  84.     def write_log(self, id, t):
  85.         if ( self.last_update is None ) or (time.time() - self.last_update > self.INTERVAL):
  86.             self._log.update(id,t)
  87.    
  88.     def commit_update(self):
  89.         self.last_update = time.time()
  90.  
  91.  
  92.  
  93. db_log = TempLog()
  94. cron_log = CronLog(db_log)
  95.  
  96.  
  97. history_action = collections.defaultdict(dict)
  98. #history_action = {}
  99.  
  100. history_temperature = {}
  101.  
  102. class BaseHttp(resource.Resource):
  103.     isLeaf = True
  104.     route = None
  105.     def getChild(self, name, request):
  106.         print name
  107.         if name == "":
  108.             return self
  109.         else:
  110.             return resource.Resource.getChild(self, name, request)
  111.  
  112. class Static(DirectoryLister):
  113.    
  114.     def __init__(self, dir):
  115.         DirectoryLister.__init__(self, dir)
  116.         for file in itertools.ifilter(lambda f: os.path.isfile(os.path.join(dir,f)), os.listdir(dir)):
  117.             self.putChild(os.path.join(file),File(os.path.join(dir,file)))
  118.  
  119. class Main(BaseHttp):
  120.     isLeaf = False
  121.     def render_GET(self,request):
  122.         return redirectTo("/web/page.html",request)
  123.  
  124. class GET_TEMP(BaseHttp):
  125.     isLeaf= False
  126.     def render_GET(self, request):
  127.         return json.dumps(history_temperature)
  128.    
  129. class GetHistoryTemp(BaseHttp):
  130.    
  131.     def __init__(self, tlog):
  132.         self.log = tlog
  133.    
  134.     @defer.inlineCallbacks
  135.     def _process(self, request, date):
  136.         history = yield self.log.get_history(date)
  137.         print history
  138.         request.write(json.dumps(history))
  139.         request.finish()
  140.    
  141.     def render_GET(self, request):
  142.         date = request.args.get("date","") or "now"
  143.  
  144.         if type(date) == list:
  145.             date = date[0]
  146.         self._process(request , date)
  147.         return server.NOT_DONE_YET
  148.        
  149.  
  150.  
  151. class WrapperWin32Serial(serial.Serial):
  152.     @property
  153.     def hComPort(self):
  154.         return self._port_handle
  155.  
  156.  
  157. class SerialArduino(protocol.Protocol):
  158.    
  159.     def __init__(self,port, speed):
  160.         self.port = port
  161.         self.speed = speed
  162.         self.callbacks = []
  163.         self.bootstraps = []
  164.         self.lock = defer.DeferredLock()
  165.         self.retry = None
  166.        
  167.     def connect(self):
  168.         try:
  169.             SerialPort(self, self.port, reactor, baudrate = self.speed)
  170.             #self.retry = None
  171.         except:
  172.             print "reconnect"
  173.             self.retry = reactor.callLater(5, self.connect)
  174.    
  175.     def connectionMade(self):
  176.         print "Connect OK", self.bootstraps
  177.         for h in self.bootstraps:
  178.             h(self)
  179.        
  180.     def addBootstrap(self, handle):
  181.         self.bootstraps.append(handle)
  182.  
  183.     def connectionLost(self,reason = 0):
  184.         print reason
  185.         for b,d in self.callbacks:
  186.             d.errback(reason)
  187.         self.callbacks = []
  188.         self.retry = reactor.callLater(5, self.connect)
  189.  
  190.     def dataReceived(self,data):
  191.         for byte in data:
  192.             self._byteReceive(byte)
  193.  
  194.     def _byteReceive(self, byte):
  195.         defer_callbacks = list(self.callbacks)
  196.         self.callbacks = []
  197.         for e,(buf,d) in enumerate(defer_callbacks):
  198.             if buf.write(byte):
  199.                 del defer_callbacks[e]
  200.                 d.callback(buf.readall())
  201.         self.callbacks += defer_callbacks
  202.            
  203.     def assyncRead(self,buffer):
  204.         if isinstance(buffer, Listener):
  205.             d = defer.Deferred()
  206.             self.callbacks.append((buffer, d))
  207.             return d
  208.        
  209.    
  210.    
  211. def startProcess(list_process):
  212.     for proc in list_process:
  213.         try:
  214.             Popen(os.path.abspath(proc),shell=True, cwd = os.getcwd())
  215.         except Exception:
  216.             print "Problem with ",proc
  217.             log.err()
  218.         else:
  219.             log.msg("Success exec process ", proc)
  220.    
  221.    
  222.    
  223. def updateTempToFile():
  224.     xml = etree.Element("temp")
  225.     for sensor, temp in history_temperature.iteritems():
  226.         sens_t = etree.Element("sensor", {"id":sensor, "name":CONFIG.get("sensors",{}).get(sensor,{}).get("alias","default")})
  227.         sens_t.text = str(temp)
  228.         xml.append(sens_t)
  229.     with open("temp.log", "w") as f:
  230.         f.write(etree.tostring(xml))
  231.    
  232.    
  233. @defer.inlineCallbacks
  234. def uartProcess(arduino):
  235.     b = BytesBuffer(2)
  236.     data = yield arduino.assyncRead(b)
  237.     last_temp = None
  238.     print data
  239.     while True:
  240.         try:
  241.             yield sleep(1)
  242.             try:
  243.                 arduino.transport.write("a")
  244.             except:
  245.                 break
  246.             buf = UntillBuffer("%")
  247.             try:
  248.                 data = (yield arduino.assyncRead(buf)).strip()
  249.             except:
  250.                 break
  251.             raw_data = data.split("\n")
  252.             for sensor_data in raw_data:
  253.                 try:
  254.                     sensor, temp = sensor_data.strip().split(" ")
  255.                     cron_log.write_log(sensor, temp)
  256.                 except:
  257.                     log.err()
  258.                 if sensor  in CONFIG.get("sensors",{}).keys():
  259.                     print sensor_data
  260.                 else:
  261.                     print u"NEW" ,sensor_data
  262.                 round_temp = int(round(float(temp)))
  263.                 history_temperature[sensor] = round_temp # последнее изменение температуры для веба
  264.                 if last_temp == round_temp: # Если температура измениась продолжаемс....
  265.                     continue
  266.                 last_temp = round_temp
  267.                 config = CONFIG.get("sensors",{}).get(sensor,{}).get("rules",{})
  268.                 for condition, actions in config.iteritems():
  269.                     c1,c2 = condition.split(":")
  270.                     c1,c2 = int(c1),int(c2)
  271.                     last_act = history_action.get(sensor,{}).get(condition)
  272.                     if not actions:
  273.                         continue
  274.                     if round_temp < c1 and last_act != c1:
  275.                         history_action[sensor][condition] = c1
  276.                         yield deferToThread(startProcess, actions["l"])
  277.                     elif round_temp > c2 and last_act != c2:
  278.                         history_action[sensor][condition] = c2
  279.                         yield deferToThread(startProcess, actions["h"])
  280.             cron_log.commit_update()
  281.             updateTempToFile()
  282.         except :
  283.             log.err()
  284.            
  285.                    
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294. @reactor.callWhenRunning
  295. @defer.inlineCallbacks
  296. def main():
  297.     yield db_log.init_db()
  298.     s = SerialArduino(CONFIG.get("config",{}).get("port","/dev/ttyUSB0"),CONFIG.get("config",{}).get("b_rate",9600))
  299.     s.addBootstrap(uartProcess)
  300.     s.connect()
  301.  
  302. if __name__ == "__main__":
  303.     global CONFIG
  304.     if platform.isWindows():
  305.         SerialPort._serialFactory = WrapperWin32Serial
  306.     with  open("config.json") as fp:
  307.         CONFIG = json.load(fp)
  308.     print CONFIG
  309.     root = Main()
  310.     root.putChild("web",Static("./web"))
  311.     root.putChild("history", GetHistoryTemp(db_log))
  312.     site =  server.Site(root)
  313.     reactor.listenTCP(CONFIG.get("config",{}).get("web_port",8081), site)
  314.     reactor.run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement