Files
ThingsBoard/RPI Docker Test/schedule.py
2024-10-04 18:53:54 -05:00

338 lines
13 KiB
Python

import array
import time
import thread
import threading
try:
import json
except:
import simplejson as json
import pickle
import datetime
from datetime import tzinfo, timedelta
ZERO = timedelta(0)
class schedule():
def __init__(self, setCallback, Q, getTime, ):
self.sets = setCallback
self.q = Q
self.getTime = getTime
print "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
print "starting scheduler"
#load any schedules from pickle file
#if we can't get it from the web, look for the pickled version
try:
with open('/root/python_firmware/drivers/schJSON.p', 'rb') as handle:
self.schedDict = pickle.load(handle)
print "found pickled dictionary"
print self.schedDict
except:
print "couldn't load devices from pickle"
self.schedDict = {}
thread.start_new_thread(self.run, ())
#[{"user":"demo@meshify.com","mac":"000CE373293D","company":"188","payload":{"name":"wipom_[00:0c:e3:73:29:3d:00:21]!.do2","value":"1","expires":"1389369695"},"msgId":4478}]
#take that object and replace the .d02 (channel name) with the channel name in the scheduler, and the value with the value, then put back into sets
#add -> update the list of scheduled events, return in time order
#del -> remove the one with the hash that was sent. [hash, hash, hash]
def run(self):
#sleep for a minute to make sure the core is ready
time.sleep(30)
try:
t = self.getTime()
except:
#try and sleep another minute
time.sleep(60)
print "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
self.initilizeAll()
print "running schedule core"
#here we will loop over the json and send on any sets we need to when we need to
#how to run this once a minute and make sure we dont miss or repeat???
#since we only support every 5 minutes of time, how about I look at it every 30 seconds and sleep for 120 if I hit an event.
while True:
try:
print "checking schedule"
#marker for if we got an event this time:
didSomethingHappen = False
#first grab the time using the gettime function
utc = UTC()
timeObj = datetime.datetime.fromtimestamp(int(self.getTime()), tz=utc)
DOW = timeObj.weekday()
min = timeObj.minute
if min < 10:
min = "0" + str(min)
hour = timeObj.hour
if hour < 10:
hour = "0" + str(hour)
tm = str(hour) + ":" + str(min)
print "here is our time and day of week:"
print tm, DOW
#its less likely that a time will match, so first lets check for hours and minutes that match
for device in self.schedDict:
mac = self.schedDict[device]['mac']
company = self.schedDict[device]['company']
name = self.schedDict[device]['name']
events = self.schedDict[device]['events']
#print "here are the events:"
#print events
for event in events:
#print "here is the event"
event = self.schedDict[device]['events'][event]
#print event
if event['t'] == tm:
print "we have a time match"
if DOW in event['d'] or str(DOW) in event['d']:
print "activating schedule event"
print ("Schedule Set: " + str(event['c']) + " To: " + str(event['v']))
didSomethingHappen = True
j = event['set']
#do the set, then send a message on the log channel that the sceduled event has taken place
try:
success = self.sets(j, sch=True)
msg = ""
if success == 0:
print "success"
msg = "Schedule Set: " + str(event['c']) + " To: " + str(event['v'])
if success == 1:
print "error 1"
msg = "Schedule FAILED (internal/driver error) to Set: " + str(event['c']) + " To: " + str(event['v'])
if success == 2:
print "error 2"
msg = "Schedule FAILED (no driver callback) to Set: " + str(event['c']) + " To: " + str(event['v'])
if msg != "":
self.sendtodb('log', msg, 0, company, mac, device)
except:
#if one breaks, keep looking
continue
#sleep for 2 minutes if you had an event, this keeps you from calling an event twice, and you can't miss another event, because it wont happen for a least 5 more min
if didSomethingHappen:
print "sleeping 2 minutes"
time.sleep(120)
else:
print "sleeping 28 seconds"
time.sleep(28)
pass
except Exception,e:
print e
time.sleep(28)
def sendtodb(self, channel, value, timestamp, company, mac, deviceName):
if int(timestamp) == 0:
timestamp = self.getTime()
try:
topic = 'meshify/db/%s/%s/%s/%s' % (company, mac, deviceName, channel)
print topic
if channel == "sch-":
#for the JSON structure I had to take off the " " around the value
msg = """[ { "value":%s, "timestamp":"%s" } ]""" % (str(value), str(timestamp))
else:
msg = """[ { "value":"%s", "timestamp":"%s" } ]""" % (str(value), str(timestamp))
print msg
self.q.put([topic, msg, 0])
except:
print "didn't work to send up MQTT data"
def message(self, channel, msg):
fullmsg = msg
#[{"user":"demo@meshify.com","mac":"000CE373293D","company":"188","payload":{"name":"wipom_[00:0c:e3:73:29:3d:00:21]!.do2","value":"1","expires":"1389369695"},"msgId":4478}]
#example value: [{'h':'0123','n':'back to running','c':'start','v': 'On','t': '13:55','d': [0,1,2,3,4,5,6]}, {'h':'0123','n':'back to running','c':'start','v': 'On','t': '13:55','d': [0,1,2,3,4,5,6]},{'h':'0123','n':'back to running','c':'start','v': 'On','t': '13:55','d': [0,1,2,3,4,5,6]}, {'h':'0123','n':'back to running','c':'start','v': 'On','t': '13:55','d': [0,1,2,3,4,5,6]} ]
#only single quotes for now can be sent
# [{
# 'h':0123,
# 'n':'back to running',
# 'c':'start',
# 'v': 'On',
# 't': '13:55',
# 'd': [0,1,2,3,4,5,6]
# }]
#channel can be sch-add or sch-del
data = msg[0]
msgId = str(data['msgId'])
user = str(data['user'])
mac = str(data['mac'])
company = str(data['company'])
d = data['payload']
name = d['name'].split('.')[0]
deviceName = name.split('_')[0]
#for testing, todo: change back
value = d['value']
if channel == "sch-add":
print "adding schedule"
value = value.replace("'", '"')
events = json.loads(value)
#first see if this device has a key in our main dictionary
if self.schedDict.has_key(name):
print "device already in dictionary"
else:
#add this device to the dictionary
print "adding device to dictionary"
self.schedDict[name] = {'events': {}, 'mac':mac, 'company':company, 'name':name}
#now it has a section for the device, lets start adding the events
returnStr = ""
for event in events:
try:
n = event['n']
fullmsg[0]['payload']['name'] = (name + "." + event['c'])
fullmsg[0]['payload']['value'] = event['v']
#set up a dictionary for the event details of this event
#consiquently this will erase an event with this same hash, but this is ok
print "here is the new key in the event"
print event['h']
self.schedDict[name]['events'][event['h']] = {'set':str(json.dumps(fullmsg)),'h':event['h'], 'n':event['n'],'c':event['c'],'v':event['v'],'t':event['t'],'d':event['d']}
print 'here is the event'
print self.schedDict[name]['events'][event['h']]
except:
returnStr += "Failed Adding Schedule Event: " + str(n) + " , "
else:
returnStr += "Success Adding Schedule Event: " + str(n) + " , "
self.sendMsgResp(returnStr, msgId)
print self.schedDict
#now send back the updated data to the web
returnJSON = self.rebuildForDevice(name)
fullmsg[0]['payload']['name'] = (name + "." + "sch-")
fullmsg[0]['payload']['value'] = returnJSON
print fullmsg
self.sendtodb('sch-', returnJSON, 0, company, mac, name)
elif channel == "sch-del":
returnStr = ""
print "deleting an event with the ID"
#in this case the value will be a list of hahses that will be deleted
value = value.replace("'", '"')
values = json.loads(value)
print values
for val in values:
try:
n = self.schedDict[name]['events'][val]['n']
except:
n = "Unknown ID"
try:
del self.schedDict[name]['events'][val]
except:
returnStr += "Failed Deleting Schedule Event: " + str(n) + " , "
else:
returnStr += "Success Deleting Schedule Event: " + str(n) + " , "
self.sendMsgResp(returnStr, msgId)
#now send back the updated data to the web
returnJSON = self.rebuildForDevice(name)
fullmsg[0]['payload']['name'] = (name + "." + "sch-")
fullmsg[0]['payload']['value'] = returnJSON
print fullmsg
self.sendtodb('sch-', returnJSON, 0, company, mac, name)
elif channel == "sch-sync":
self.sendMsgResp("Schedule Synced", msgId)
self.initilizeAll()
#update persistant dictionary
with open('/root/python_firmware/drivers/schJSON.p', 'wb') as handle:
pickle.dump(self.schedDict, handle)
#thread.start_new_thread(self.sets, (j,))
def sendMsgResp(self, val, msgId):
lc = self.getTime()
value = val
msg = """[ { "value":"%s", "timestamp":"%s", "msgId":"%s" } ]""" % (value, str(lc), msgId)
topic = "meshify/responses/" + msgId
self.q.put([topic, str(msg), 2])
def rebuildForDevice(self, name):
print "building json for return message"
newJSON = []
for event in self.schedDict[name]['events']:
print event
print self.schedDict[name]['events'][event]['h'], self.schedDict[name]['events'][event]['n'], self.schedDict[name]['events'][event]['c'], self.schedDict[name]['events'][event]['v'], self.schedDict[name]['events'][event]['t'], self.schedDict[name]['events'][event]['d']
newJSON.append({'h':self.schedDict[name]['events'][event]['h'],
'n':self.schedDict[name]['events'][event]['n'],
'c':self.schedDict[name]['events'][event]['c'],
'v':self.schedDict[name]['events'][event]['v'],
't':self.schedDict[name]['events'][event]['t'],
'd':self.schedDict[name]['events'][event]['d'],
})
data = str(json.dumps(newJSON))
print "here is the device JSON"
print data
return data
def initilizeAll(self):
#here I want to send all of the current schedules for all devices on startup, this could use a lot of data maybe
print "updating everything on startup"
for name in self.schedDict:
mac = self.schedDict[name]['mac']
company = self.schedDict[name]['company']
name = self.schedDict[name]['name']
msg = self.rebuildForDevice(name)
self.sendtodb('sch-', msg, 0, company, mac, name)
pass
class UTC(tzinfo):
"""UTC"""
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()