def command(message): msgList = message.split('_') if(msgList[0] == "wifiplug"): try: if('add' in msgList[1]): addNewPlug(int(msgList[2])) return id = int(msgList[1]) - 1 print ips[id] if(msgList[2] == "on"): plug = SmartPlug(ips[id]) print("Current state: %s" % plug.state) plug.state = "ON" return if(msgList[2] == "off"): plug = SmartPlug(ips[id]) print("Current state: %s" % plug.state) plug.state = "OFF" return except ValueError: logging.warning('Invalid command: Incorrect id format') return except Exception as e: logging.warning(e) return
def action(self, action, timeout=None): action = action.upper() try: settings.plugins.lights[self.room] except Exception: return try: self.isOpen(9999) except Exception: return if not self.post.ack(): return type = settings.plugins.lights[self.room]['type'] if type == 'plug': emoji = ':electric_plug:' tplinklight = SmartPlug( settings.plugins.lights[self.room]['ipaddr']) else: type = 'light' emoji = ':bulb:' tplinklight = SmartBulb( settings.plugins.lights[self.room]['ipaddr']) if eval(os.environ['DEBUG']): debug = "[{}] ".format(device_name) else: debug = "" room_name = self.room.capitalize() if room_name.endswith('s'): room_name = room_name[:-1] + "'" + room_name[-1:] chat.post("{} {}Switching {} {} {}.".format(emoji, debug, room_name, type, action.lower())) tplinklight.state = action if timeout is not None: sleep(float(timeout) * 60) tplinklight.state = 'OFF' self.post.unack()
def toggle(self): try: settings.plugins.lights[self.room] except Exception: return try: self.isOpen(9999) except Exception: return if not self.post.ack(): return type = settings.plugins.lights[self.room]['type'] if type == 'plug': emoji = ':electric_plug:' tplinklight = SmartPlug( settings.plugins.lights[self.room]['ipaddr']) else: emoji = ':bulb:' type = 'light' tplinklight = SmartBulb( settings.plugins.lights[self.room]['ipaddr']) if eval(os.environ['DEBUG']): debug = "[{}] ".format(device_name) else: debug = "" if tplinklight.state == "OFF": action = "ON" else: action = "OFF" room_name = self.room.capitalize() if room_name.endswith('s'): room_name = room_name[:-1] + "'" + room_name[-1:] chat.post("{} {}Switching {} {} {}.".format(emoji, debug, room_name, type, action.lower())) tplinklight.state = action self.post.unack()
def live_check(): # Please enter the IP of the tplink switches and the host associated to it. # example 'miner 01':{'switch':'192.168.1.10','host':'192.168.1.11' # The "xx" needs to be removed and replaced with the IP of your devices. If you have less/more # devices, then add or remove to this dataframe as needed, each must be seperated with a comma # and the end must have "}}" device = {'miner 01':{'switch':'192.168.1.xx','host':'192.168.1.xx'}, 'miner 02':{'switch':'192.168.1.xx', 'host':'192.168.1.xx'}, 'miner 03':{'switch':'192.168.1.xx', 'host':'192.168.1.xx'}, 'miner 04': {'switch': '192.168.1.xx', 'host': '192.168.1.xx'}} for each in device: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #print () miners = device[each] #print (miners['switch']) smartplug = SmartPlug(str(miners['switch'])) print(smartplug.alias + " -- Host IP: "+ miners['host'] + " -- Smart Plug IP: " + miners['switch'] + " : ") print ('Testing SSH on ...' + miners['host']) # Change 22 to 3389 for windows, although that is not tested in this script, it should work by theory. results = s.connect_ex((miners['host'], 22)) #print (results) if results == 0: print ("Port 22 reachable\n") #smartplug = SmartPlug(each) #print(smartplug.alias) #notifemail(str(smartplug.alias)) else: # So the reason this is setup to make the call 3 times is due to how the protocol of a tplink device works. # These devices use udp to communicate so only calling ity once can cause the script to fail in it's action # also note that this takes advantage of a security flaw in the tplink design. These calls are happening # unathenticated, meaning anyone on your network can do this to your devices. print("SSH Closed") smartplug.state = "OFF" time.sleep(1) smartplug.state = "OFF" time.sleep(1) smartplug.state = "OFF" time.sleep(10) print (smartplug.state) smartplug.state = "ON" smartplug.state = "ON" time.sleep(1) smartplug.state = "ON" time.sleep(10) print(smartplug.state) print (smartplug.alias + " NEEDED TO BE RESTARTED\n") # sends the email, comment out if you don't want that functionality notifemail(str(smartplug.alias)) #script sleeps for a bit time.sleep(30) s.close()
def tpTogglePlug(self, ip): plug = SmartPlug(ip) if plug.state == 'OFF': plug.state = 'ON' else: plug.state = 'OFF'
def main(): import schedule from schedule import schedule # Input variables # Determine which rooms are rotated (only allowed to be on one at a time) rotate_plugnames = ['OBED', 'LBED'] # Temperature settings. Setback is change in setting temp for Ohmhour DR event. Must be a negative number. deadband = 0.2 setback = -3.0 # Get authorizations auth_dict = creds() # Fresh tokens on program start ecobee_token_response = ecobee_tokens(True, datetime.datetime.min) auth = ecobee_token_response[0] last_refresh_time = ecobee_token_response[1] # Set up Ohmconnect call http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where()) oc = [False] # initial timestamp timestamp = '{:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now()) # Initial ecobee API call to populate room class # TODO - refactor Ecobee API call and error handling (make consistent) as function # TODO - Use /thermostatSummary URL to get Runtime Revision and refresh only when this changes try: thermostat_url = 'https://api.ecobee.com/1/thermostat?' payload = {'json': '{"selection":{"selectionType":"registered","includeSensors":"true"}}'} header = {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': auth} response = requests.get(thermostat_url, headers=header, params=payload) except TimeoutError: err_string = (str(timestamp) + ' Timeout error in ecobee data call') + "\r" print(err_string) send_twilio_msg(err_string) log = open('log.txt', 'a+') log.write(err_string) log.close() data = response.json() # Discover all temperature sensors tempdict = get_sensors(data) sensornames = list(tempdict.keys()) if len(tempdict) == 0: print(data) sys.exit("no temperature sensors detected") else: pass # Discover all plugs TODO consolidate into getplugs so it returns a dictionary of valid plug objects plugip = {} plugnames = [] named_flag = False discover = get_plugs(plugip, plugnames, named_flag) plugip = discover[0] plugnames = discover[1] named_flag = True plugdict = {} for name in plugip: try: plugdict[name] = SmartPlug(plugip[name]) except: pass # Create list of valid rooms with both active sensors and plugs namelist = set(sensornames).intersection(plugnames) # Define Room class class Room: def __init__(self, name, temp, status, temp_high, temp_low): self.name = name self.temp = temp self.status = status self.temp_high = temp_high self.temp_low = temp_low # Initialize schedule and temperatures setdict = setpoints(timestamp) # Define rooms and room dictionary roomdict = {} for name in namelist: roomdict[name] = Room(name, tempdict[name], 'OFF', setdict[name]+deadband, setdict[name]) # Initialize error counter & loop status sensor_error_count = 0 last_loop_sched = True start_turn = 0 # Get last schedule modification time mtime = os.path.getmtime('schedule.py') # Start main loop while True: # Automatically reload schedule to capture changes mtime_now = os.path.getmtime('schedule.py') if mtime_now != mtime: importlib.reload(sys.modules['schedule']) from schedule import schedule print("Schedule Updated") else: pass mtime = mtime_now # Token refresh ecobee_token_response = ecobee_tokens(False, last_refresh_time) last_refresh_time = ecobee_token_response[1] # time handling timestamp = '{:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now()) # Determine Schedule or Sleep mode setdict = setpoints(timestamp) setvals = [] for name in namelist: setvals.append(setdict[name]) if len(setvals) == setvals.count(-999): sched = False else: sched = True # Schedule (active) mode if sched is True: # Token refresh ecobee_token_response = ecobee_tokens(False, last_refresh_time) auth = ecobee_token_response[0] last_refresh_time = ecobee_token_response[1] # Call EcoBee API to get data # TODO refactor to use thermostat Summary / Runtime Revision and change wehn values update. # TODO at some point estimate temperature (ML?) try: thermostat_url = 'https://api.ecobee.com/1/thermostat?' payload = {'json': '{"selection":{"selectionType":"registered","includeSensors":"true"}}'} header = {'Content-Type': 'application/json;charset=UTF-8', 'Authorization': auth} response = requests.get(thermostat_url, headers=header, params=payload) data = response.json() except: err_string = (str(timestamp) + 'Error in ecobee data call') + "\r" print(err_string) sleep(30) continue # Update temperature readings with error handling tempdict = get_sensors(data) if len(tempdict) == 0: print(data) sensor_error_count = sensor_error_count + 1 if sensor_error_count == 1: send_twilio_msg("Warning - sensor temps not updating") elif sensor_error_count == 11: send_twilio_msg("Temp reading failure. Program exited.") sys.exit("Temp reading failure. Program exited.") else: pass sleep(60) continue else: if sensor_error_count > 0: send_twilio_msg("Sensor issue resolved") else: pass sensor_error_count = 0 pass # Get Ohmconnect status TODO use: get_OC(http) try: oc_url = auth_dict['ohmconnect_url'] r = http.request('GET', oc_url) data = r.data root = et.fromstring(data) oc_txt = root[1].text if oc_txt == 'True': oc_state = True else: oc_state = False except: oc_state = False # Determine Ohmconnect state and setback offset # TODO use dequeue instead oc.insert(0,oc_state) last_oc = oc.pop() if oc_state == last_oc: offset = 0 elif oc_state == True: offset = setback else: offset = -setback # Decision logic and set booleans for switches # Plug status is updated separately from state to reduce calls to plug endpoints and allow rotation of heater operation offline_list = [] rotate_active = rotate_plugnames for name in namelist: # Determine high and low setpoints for iteration based on deadband and offset roomdict[name].temp = tempdict[name] roomdict[name].temp_low = setdict[name] roomdict[name].temp_high = setdict[name]+deadband roomdict[name].temp_high = roomdict[name].temp_high + offset roomdict[name].temp_low = roomdict[name].temp_low + offset # Determine each room's status (On or Off) if schedule(name,'All') is True: if roomdict[name].temp == 999: print('Warning: bad temp reading in ', name) roomdict[name].status = roomdict[name].status elif roomdict[name].temp <= roomdict[name].temp_low: roomdict[name].status = "ON" elif roomdict[name].temp > roomdict[name].temp_high: roomdict[name].status = "OFF" else: roomdict[name].status = roomdict[name].status else: roomdict[name].status = "OFF" print(name," Room Is Off") # Update state for plugs in rotation if not rotate_active: # Handles the case of an empty rotate_active list pass elif name in rotate_active: # print(rotate_active) # For debugging status = roomdict[name].status plug_rotation_return = plug_rotation(rotate_active, plugdict, name, status, start_turn) roomdict[name].status = plug_rotation_return[0] rotate_active = plug_rotation_return[1] else: pass # Set plug state from status, with rediscovery on fail try: plugdict[name].state = roomdict[name].status except: plugip = get_plugs(plugip, plugnames, named_flag)[0] try: plugdict[name] = SmartPlug(plugip[name]) except: offline_list.append(name) start_turn = plug_rotation_return[2]+1 # statusmsg = str(offline_list)+" Offline" #TODO bring statusmsg back # Write console & log stat_str = "\n" + "Timestamp: " + str(timestamp) + "\n" +"\n" log_str = str(timestamp) + ", " for name in namelist: stat_str += (str(name) + " Set: " + str(roomdict[name].temp_low) + " Temp: " + str(roomdict[name].temp) + " Heat: " + str(roomdict[name].status) + "\n") log_str += (str(name) + ", " + str(roomdict[name].temp_low) + ", " + str(roomdict[name].temp) + ", " + str(roomdict[name].status) + ", ") # TODO bring statusmsg back here too # stat_str += ("Mode: " + statusmsg + "\n" + "Ohmconnect Status: " + str(oc_txt)) # log_str += ("Mode: " + statusmsg + ", " + "Ohmconnect Status: " + str(oc_txt) + "\n") log = open("log.txt", "a+") log.write(log_str) log.close() print(stat_str + "\r") last_loop_sched = True # If outside of the schedule enter sleep mode. No logging in sleep mode. elif last_loop_sched is True and sched is False: # Turn all plugs off if possible for name in namelist: try: if roomdict[name].status == 'ON': plugdict[name].state = 'OFF' roomdict[name].status = plugdict[name].state print(name, 'turned off') else: pass except: overrun_warn_msg = str('Warning, {0} offline -- could not be turned off automatically'.format(name)) send_twilio_msg(overrun_warn_msg) print(overrun_warn_msg) print('Sleep Mode') last_loop_sched = False else: pass sleep(looptime) continue
#!/usr/bin/python3 #general imports import time import sys #import needed for plug control from pyHS100 import SmartPlug, SmartBulb from pprint import pformat as pf #ensure correct number of arguments are passed in if len(sys.argv) != 2: print("please use this format: morning_heat.py <time_in_minutes>") exit() #assign aguements to variables script_name = sys.argv[0] on_time = int(sys.argv[1]) #abstracted variables plug_ip = "10.0.2.41" #instantiate plug object for heater heater = SmartPlug(plug_ip) #turn on for specified time heater.state = "ON" time.sleep(60 * on_time) heater.state = "OFF"
#!/usr/bin/env python # coding=utf-8 # Step 1 import sys from pyHS100 import SmartPlug, SmartBulb from pprint import pformat as pf plug = SmartPlug(sys.argv[1]) plug.state = sys.argv[2]