def sensor_export(): output = {} for sensor in sensors: voltage, wattage = [0, 0] # Get Sensor Object: try: sensor_object = pyHS100.SmartPlug(sensors[sensor]) consumption = sensor_object.get_emeter_realtime() voltage, wattage = consumption['voltage_mv'] / 1000, consumption[ 'power_mw'] / 1000 except Exception as e: print('Error: Cannot get power status on %s. %s' % (sensor, e)) finally: energy = energy_calculator(wattage) output.update({ sensor: { 'volts': voltage, 'watts': wattage, 'kwh': energy[0], 'day_rate': energy[1] } }) return output
def device_setup(): global plug, denon, roku, trigger_map trigger_map = TriggerMap() denon = DenonConnection(device_details.denon_ip_address(), "23", trigger_map) roku = Roku.discover(timeout=5)[0] plug_ip = list(pyHS100.Discover().discover())[0] plug = pyHS100.SmartPlug(plug_ip)
def check_recording(self, ): """ call helper thread, best or ok in main -- used by smart_plug not smart_plug_graphing if recording then record the data in db for now do not assume timer is running call from ht polling action """ msg = "SmartPlugAdapter.check_recording " AppGlobal.log_if_wrong_thread(threading.get_ident(), msg=msg, main=False) if not (self.recording or self.monitor): return # msg = f"?ht? adapter check_recording " # AppGlobal.what_thread( threading.get_ident(), msg, 20 ) now = time.time() if now < self.next_record_time: # or monitor time return self.last_record_time = now self.next_record_time = now + self.delta_t try: plug = pyHS100.SmartPlug(self.tcpip) plug_data = plug.get_emeter_realtime() # ?? could add plug state - on off,..... # id = f"{self.name}{self.last_record_time}r" # print ( f"record data {id}:{plug_data})" ) rnd = "%.2f" % plug_data["power"] msg = f'{rnd} watts' #!! bit of rounding would be nice here self.gui_tk_label_2.config(text=msg) except pyHS100.smartdevice.SmartDeviceException as exception: # look up correct exception self.timer_on = False #self.record_off() to much messaging and will throw own error msg = f"failed to communicate with plug - record off for: {self.name} {self.tcpip}" AppGlobal.gui.print_info_string(msg) return if AppGlobal.graph_live_flag and self.monitor and self.live_graph_ready: # print( "check_recording" ) self.graphing_new_data = True #!! normalized and unnormalize data self.gd_time.append(self.last_record_time) self.gd_time_adj.append( AppGlobal.graph_live.rescale_time_function( self.last_record_time)) #?? make local ref?? self.gd_power.append(plug_data["power"]) if self.recording: db_data = ((self.name, self.last_record_time, "r", "?", plug_data["voltage"], plug_data["current"], plug_data["power"], plug_data["total"]), ) self.insert_measurements(db_data)
def get_light_state(): ''' Provides a helper to get the external light state (boolean). ''' plug = SmartHome.SmartPlug(SENSOR_IP_LIGHT) # Where 0.0 is 'Light Off' and 1.0 is 'Light On'. if plug.get_sysinfo()['relay_state'] == 0: return 0.0 else: return 1.0
def get_smartplug_state(name): from lumacode import get_smartdevices try: device = pyHS100.SmartPlug( get_smartdevices.address(category='smartplugs', name=name)) state = remap_state(device.state) except Exception as e: state = 0 print('Error on %s: %s' % (name, e)) return state
def on(self, ): """ mutator plug on call from ht or gt manage exception: plug might not be there ....... """ try: plug = pyHS100.SmartPlug(self.tcpip) plug.turn_on() self.display_msg("Plug On") except pyHS100.smartdevice.SmartDeviceException as exception: msg = "failed to communicate with plug" self.display_msg(msg) msg = msg + ": " + self.name AppGlobal.gui.print_info_string(msg)
def api_state(self): plug = pyHS100.SmartPlug("192.168.0.109") if request.method == 'POST': # POST requests are for setting the light state light_state_actions = {True: plug.turn_on, False: plug.turn_off} light_state = request.form.get('light_state', 'false') == "true" light_state_actions[light_state]() #set_state_on = 'light_state' in request.form.keys() and request.form.get('light_state', 'false') == "true" #if set_state_on: # plug.turn_on() #else: # plug.turn_off() return ('', 204) elif request.method == 'GET': # GET requests are for reading the light state return_dict = {"light_state": plug.state == "ON"} return json.dumps(return_dict)
def get_full_info( tcpip ): """ !! get info from a device return an ordered dict of all info we know how to get from device if device not found then will have full_info["device"] = "failed to communicate" and length <= 3 """ #print("get_full_info") full_info = {} full_info["tcpip"] = tcpip try: plug = pyHS100.SmartPlug( tcpip ) # some info may be duplicated but that just loweres efficiency # additional dicts add_dict = plug.hw_info full_info.update( add_dict ) full_info.update( plug.sys_info ) full_info.update( plug.location ) full_info.update( plug.timezone ) # additional individual items full_info["alias"] = plug.alias full_info["device_type"] = plug.device_type full_info["time"] = plug.time full_info["is_plug"] = plug.is_plug full_info["is_strip"] = plug.is_strip full_info["is_variable_color_temp"] = plug.is_variable_color_temp full_info["is_bulb"] = plug.is_bulb except Exception as exception: # look up correct exception pass # point here is just to skip it # msg = "full_info failed to communicate with plug" # print( f"type(exception ) {exception} " ) full_info["device"] = "failed to communicate" # log? #print( msg ) #raise # consider a sort into an ordered dict #return full_info od = collections.OrderedDict( sorted( full_info.items(), key=lambda t: t[0] )) return od
def scan_for_plugs( start_tcpip, start_tcpip_ix, end_tcpip_ix, max_plugs = 0, msg_function = None ): """ scan a range of tcpip address for plugs scan_for_plugs( "192.168.0.", 209, 210, max_plugs = 0 ): msg_function a function of one arg with a string as msg see call_msg_function ... None and it is ignored a plug is anything that responds to the plug protocol seems to take on order of 5 sec for each attempt that fails return list of tcpip address with plugs could use function scan_a_plug but not really much code saved ?? """ found_list = [] for ix in range( start_tcpip_ix, end_tcpip_ix ): tcpip = f"{start_tcpip}{ix}" msg = f"probe: {tcpip}" call_msg_function( msg_function, msg ) try: plug = pyHS100.SmartPlug( tcpip ) info = plug.hw_info msg = f"found device at: {tcpip}" call_msg_function( msg_function, msg ) found_list.append( tcpip ) if max_plugs == 0: continue if len( found_list ) >= max_plugs: break # # print( msg ) # AppGlobal.gui.print_info_string( msg ) # may save event # full_info = "no info" # full_info = self.get_full_info( tcpip ) # print( full_info ) #except Exception as exception: # look up correct exception except pyHS100.smartdevice.SmartDeviceException as exception: print( f"{type(exception )} {exception} " ) msg = f"failed to communicate with plug at {tcpip}" print( msg ) msg = f" no device at: {tcpip}" # indented call_msg_function( msg_function, msg ) return found_list
def scan_a_plug( tcpip, msg_function = None ): """ scan a range of tcpip address for plugs scan_for_plugs( "192.168.0.", 209, 210, max_plugs = 0 ): msg_function a function of one arg with a string as msg see call_msg_function ... None and it is ignored a plug is anything that responds to the plug protocol seems to take on order of 5 sec for each attempt that fails return list of tcpip address with plugs """ ret = False # True if plug is found at the tcpip msg = f"probe: {tcpip}" call_msg_function( msg_function, msg ) try: plug = pyHS100.SmartPlug( tcpip ) info = plug.hw_info ret = True except pyHS100.smartdevice.SmartDeviceException as exception: print( f"{type(exception )} {exception} " ) msg = f"failed to communicate with plug at {tcpip}" print( msg ) return ret
def off(self, ): """ mutator off from on or from timer running, may have a conflict as this may be called from either thread ht or gt if timer is on turn it off """ try: self.timer_on = False plug = pyHS100.SmartPlug(self.tcpip) plug.turn_off() self.display_msg("Plug Off") if self.timer_on: self.timer_on = False msg = "Plug off and Timer Off" # print( msg ) AppGlobal.gui.print_info_string(msg) # may save event except pyHS100.smartdevice.SmartDeviceException as exception: msg = "failed to communicate with plug {self.tcpip}" self.display_msg(msg) msg = msg + ": " + self.name AppGlobal.gui.print_info_string(msg)
def monitorDevice(config, device): try: state = State.AWAKE next_state = state retries = 0 notify_state = NotifyState.ONLINE while True: previous_state = state state = next_state if state == State.AWAKE: try: host = socket.gethostbyname(device.host) socket.create_connection((host, device.port), SOCKET_TIMEOUT).close() if notify_state != NotifyState.ONLINE: notify_state = NotifyState.ONLINE notify(config, '{device.name} is ONLINE', device = device) if previous_state != state.AWAKE or retries > 0: log('Device is now up', device = device) retries = 0 except (socket.timeout, socket.error, ConnectionError): log('No response, attempt {attempt}/{device.retries}', device = device, attempt = retries + 1) retries = retries + 1 if retries >= device.retries: if notify_state != NotifyState.OFFLINE: notify_state = NotifyState.OFFLINE notify(config, '{device.name} is OFFLINE', device = device) next_state = State.POWERING_OFF continue time.sleep(device.check_interval) elif state == State.POWERING_OFF: try: host = socket.gethostbyname(device.plug_host) pyHS100.SmartPlug(host).turn_off() log('Powered off', device = device) next_state = State.POWER_OFF except (pyHS100.SmartDeviceException, socket.error) as e: log('Failed to power off: {exception}', device = device, exception = e) # Sleep, unless this was caused by a timeout if not isinstance(e.__cause__, socket.timeout): time.sleep(SOCKET_TIMEOUT) elif state == State.POWER_OFF: log('Waiting {device.cycle_time} seconds for power cycle', device = device) time.sleep(device.cycle_time) next_state = State.POWERING_ON elif state == State.POWERING_ON: try: host = socket.gethostbyname(device.plug_host) pyHS100.SmartPlug(host).turn_on() log('Powered on', device = device) next_state = State.REBOOTING except (pyHS100.SmartDeviceException, socket.error) as e: log('Failed to power on: {exception}', device = device, exception = e) # Sleep, unless this was caused by a timeout if not isinstance(e.__cause__, socket.timeout): time.sleep(SOCKET_TIMEOUT) elif state == State.REBOOTING: log('Waiting {device.boot_time} seconds for reboot', device = device) time.sleep(device.boot_time) next_state = State.AWAKE retries = 0 except Exception as e: log('Got exception while monitoring: {exception}', device = device, exception = e)
# Collection of functions for interfacing with smart devices # pyHS100 library for TP-Link devices import pyHS100 from threading import Thread # Initialise smart device objects bedside_light = pyHS100.SmartPlug('10.0.0.61') sound_system = pyHS100.SmartPlug('10.0.0.62') # Dictionary storing states - True = on smart_device_states = {bedside_light: False, sound_system: False} # Body head and tail body_head = (b'<body bgcolor=white>' + b'<p>Basic control of network connected devices</p>') body_tail = b'</body>' # HTML link syntax repeatable parts link_0 = b'<a href="' link_1 = b'"><img src="' link_2 = b'" style="width:200px;height:120px;border:0;"></a>' ''' function to return a dictionary with the states of the smart devices ''' def getDeviceStates(): smart_device_states['bedside_light'] = bedside_light.is_on smart_device_states['sound_system'] = sound_system.is_on return smart_device_states
logger = logging.getLogger(__name__) logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', filename=FILENAME, level=logging.INFO) logger.setLevel( logging.INFO) #change to logging.DEBUG or logging.INFO or logging.CRITICAL t_TOKEN = "xxx" t_CHATID = xxx plug_LIGHT = "xxx.xxx.xxx.xxx" plug_DESKTOP = "xxx.xxx.xxx.xxx" p_light = pyHS100.SmartPlug(plug_LIGHT) p_desktop = pyHS100.SmartPlug(plug_DESKTOP) light_name = ['light', 'living room', 'living room light'] desk_name = ['desk', 'desktop'] def flip_state(p_obj): if p_obj.state == 'ON': p_obj.turn_off() return p_obj.state else: p_obj.turn_on() return p_obj.state
def cb_device_action( self, button_ix, action ): """ process devices perhaps on, off timer , see lambda setup in button creation maybe decode string in adapter as well """ # print( f"controller.cb_device_action {button_ix}, {action}" ) # check for valid index -- may be overly defensive, but so what if button_ix < len( AppGlobal.device_list ): i_device = AppGlobal.smartplug_adapter_list[ button_ix ] tcpip = i_device.tcpip plug = pyHS100.SmartPlug( tcpip ) else: msg = f"invalid device index{button_ix}" self.gui.print_info_string( msg ) self.logger.info( msg ) return # test getting time # gui_combo = i_device.gui_tk_combo # combo_contents = gui_combo.get() # print(f"combo_contents: {combo_contents}, {type(combo_contents)}") # wrap actions in try except and capture error info if action == "info": # move code to device adapter #self.gui.print_info_string( tcpip ) #info = str( plug.hw_info ) # need to process this into something nice -- is this subset of get_sysinfo() info = "Full device info: \n" + plug_util.dict_to_str( plug_util.get_full_info( tcpip ) ) #print( type( info ) ) self.gui.print_info_string( info ) elif action == "start": # may make synonymous with on ?? i_device.start_timer() elif action == "cb_on": i_device.cb_on() elif action == "mon": i_device.cb_mon() elif action == "record": i_device.cb_record() elif action == "on": i_device.on() elif action == "off": i_device.off() # msg = f"Plug is_on: {plug.is_on }" # self.gui.print_info_string( msg ) elif action == "record_on": # !! check first for db file exists i_device.record_on() # msg = f"Record on plug is on : {plug.is_on }" # self.gui.print_info_string( msg ) elif action == "record_off": i_device.record_off() # msg = f"Record off plug is on : {plug.is_on }" # self.gui.print_info_string( msg ) else: msg = f"invalid action {action}" self.gui.print_info_string( msg )